Java 8, 756 bytes
import java.awt.*;v->new Frame(){void t(Graphics g,String s,int x,int y){g.drawString(s,x,y);}public void paint(Graphics g){g.setFont(new Font("Hei",0,30));t(g,"N",289,80);t(g,"E",553,341);t(g,"S",290,605);t(g,"W",20,341);t(g,"NE",434,186);t(g,"SE",437,496);t(g,"SW",120,498);t(g,"NW",121,186);g.setColor(new Color(229,229,229));g.fillPolygon(new int[]{300,346,442,390,550,390,442,346,300,254,158,210,50,210,158,254},new int[]{80,240,188,284,330,376,472,420,580,420,472,376,330,284,188,240},16);g.setColor(new Color(153,153,255));g.fillPolygon(new int[]{300,158,254,244,50,300,158,210,244,300,300,442,346,356,550,300,442,390,356,300},new int[]{330,188,240,274,330,330,472,376,386,580,330,472,420,386,330,330,188,284,274,80},20);}{setSize(600,630);show();}}
Output:
Explanation:
Code explanation:
import java.awt.*; // Required import for Frame, Graphics, Font, and Color
v-> // Method with empty unused parameter and Frame return-type
new Frame(){ // Create a new Frame
void t(Graphics g,String s,int x,int y){
// Create a temp method to reduce bytes:
g.drawString(s,x,y);} // To draw the given text at the given coordinate
public void paint(Graphics g){
// Overwrite the Frame's default paint method:
g.setFont(new Font("Hei",0,30));
// Set the Font to size 30
// (I've used Font "Hei" here, but "Kai" could be used as
// well for the same byte-count)
t(g,"N",289,80); // Draw the text "N"
t(g,"E",553,341); // Draw the "E"
t(g,"S",290,605); // Draw the "S"
t(g,"W",20,341); // Draw the "W"
t(g,"NE",434,186); // Draw the "NE"
t(g,"SE",437,496); // Draw the "SE"
t(g,"SW",120,498); // Draw the "SW"
t(g,"NW",121,186); // Draw the "NW"
g.setColor(new Color(229,229,229));
// Change the color to grey
// (the default color was black, which is why we started
// with the texts)
g.fillPolygon(new int[]{300,346,442,390,550,390,442,346,300,254,158,210,50,210,158,254},new int[]{80,240,188,284,330,376,472,420,580,420,472,376,330,284,188,240},16);
// Draw the 8-pointed star
g.setColor(new Color(153,153,255));
// Change the color to light purple
g.fillPolygon(new int[]{300,158,254,244,50,300,158,210,244,300,300,442,346,356,550,300,442,390,356,300},new int[]{330,188,240,274,330,330,472,376,386,580,330,472,420,386,330,330,188,284,274,80},20);}
// Draw a single shape as explained below
{ // In an inner code block:
setSize(600,630); // Set the size of the Frame
show();}} // And show the Frame
Calculations:
Although Java has ways to draw based on rotations, it would increase the byte-count substantial in comparison to this straight-forward approach. There is however one main disadvantage about using this shorter approach: I have to calculate all \$x,y\$-coordinates manually..
So, here's how I did that:
I first used the units as is, since that was easier to calculate with. I've put the center at position \$150,150\$ and started calculating from there.
1) Calculate the coordinates of the tips of the star at N/E/S/W:
This is not too hard. With the center at \$150,150\$ and \$\frac{\color{red}{c}}{2} = 125\$, we'll have the following points:
\$N=150,25\$
\$E=275,150\$
\$S=150,275\$
\$W=25,100\$
2) Calculate the coordinates of the tips of the star at NE/SE/SW/NW:
Again, we know the center is at \$150,150\$ and we also know \$\frac{\color{blue}{d}}{2}=100\$. We can make a triangle calculation with the angles being 90, 45, and 45 like this:
\$n=\frac{100}{2}\sqrt{2}=70.710\dots\$
(where \$m\$ are the sides \$b\$ and \$c\$ in the triangle above)
Knowing the \$n\$, we have the following points:
\$NE=150+m,150-m=220.710\dots,79.289\dots\$
\$SE=150+m,150+m=220.710\dots,220.710\dots\$
\$SW=150-m,150+m=79.289\dots,220.710\dots\$
\$NW=150-m,150-m=79.289\dots,79.289\dots\$
3) Calculate the coordinates of the points between the center and the NE/SE/SW/NW tips:
We again know the center \$150,150\$ and also \$\color{violet}{e}=40\$, so we can make a similar calculation as in step 2:
\$n=\frac{40}{2}\sqrt{2}=28.284\dots\$
And use that to calculate the points:
\$NE_{center}=150+n,150-n=178.284\dots,121.715\dots\$
\$SE_{center}=150+n,150+n=178.284\dots,178.284\dots\$
\$SW_{center}=150-n,150+n=121.715\dots,178.284\dots\$
\$NW_{center}=150-n,150-n=121.715\dots,121.715\dots\$
4) Calculate the coordinates of the remaining points:
Now all that's left are the points at the concaved intersection of the edges of the star, which are circled in red here:
Since we know the center \$150\$ and \$\color{lightblue}{f}=45\$, a portion of these coordinates aren't hard to calculate. The other part of the coordinates requires some calculations, though..
In the picture above, we know the following things beforehand:
- Red line: \$\frac{\color{red}{c}}{2}=125\$
- Both orange lines: \$n=\frac{40}{2}\sqrt{2}=28.284\dots\$
And what we want to calculate is the thick vertical blue line of the small purple triangle.
We start with the horizontal line of the larger green triangle:
\$o=125-n=96.715\dots\$
Using what we know now, we can calculate the black angle of the large green triangle as follows:
\$t=\sqrt{n^2+o^2-2no\times\cos(90)}=100.765\dots\$
\$A=\arccos(\frac{t^2+o^2-n^2}{2to})=16.301\dots\$
Then we can calculate the light blue angle of the small purple triangle:
\$B=90-16.301\dots=73.699\dots\$
As well as the horizontal line of the small purple triangle:
\$p=45-n=16.716\dots\$
Which we can then both use to calculate the height of the thick blue line of the small purple triangle:
\$q=p\frac{\sin(A)}{\sin(B)}=4.888\dots\$
After which we can finally calculate the final coordinates of these red dots, using the center and the points we've calculated in step 2:
\$NE_N=178.284\dots-q,150-\color{lightblue}{f}=173.395\dots,105\$
\$NE_E=150+\color{lightblue}{f},121.715\dots+q=195,126.604\dots\$
\$SE_E=150+\color{lightblue}{f},178.284\dots-q=195,173.395\dots\$
\$SE_S=178.284\dots-q,150+\color{lightblue}{f}=173.395\dots,195\$
\$SW_S=121.715\dots+q,150+\color{lightblue}{f}=126.604\dots,195\$
\$SW_W=150-\color{lightblue}{f},178.284\dots-q=105,173.395\dots\$
\$NW_W=150-\color{lightblue}{f},121.715\dots+q=105,126.604\dots\$
\$NW_N=121.715\dots+q,150-\color{lightblue}{f}=126.604\dots,105\$
We now have all the coordinates of the points we need, so we can draw the shape on the screen. We do this with the Graphics#fillPolygon(int[],int[],int)
-method, which takes two integer-arrays for all \$x\$- and \$y\$-coordinates respectively, as well as an integer being the amount of points. The grey star is therefore drawn using the following \$x,y\$-coordinates:
\$[[150,25],[173,105],[221,79],[195,127],\$
\$[275,150],[195,173],[221,221],[173,195],\$
\$[150,275],[127,195],[79,221],[105,173],\$
\$[25,150],[105,127],[79,79],[127,105]]\$:
We then draw a single shape for the light purple parts, and the following \$x,y\$-coordinates:
\$[[150,150],[79,79],[127,105],[122,122],[25,150],\$
\$[150,150],[79,221],[105,173],[122,178],[150,275],\$
\$[150,150],[221,221],[173,195],[178,178],[275,150],\$
\$[150,150],[221,79],[195,127],[178,122],[150,25]]\$:
A quarter of this shape goes from the center to point \$NW\$; then to point \$NW_N\$; then \$NW_{center}\$; then \$W\$; and then back to the center again:
And the entire shape is drawn by continuing in a similar fashion.
After that I've doubled everything, because the challenge description states the square should be at least 400 by 400 pixels, and in addition all \$y\$-coordinates are increased by \$30\$, because we draw directly on the frame and we still have the Window-bar at the top to consider (outside codegolf you would add a Panel to the Frame, and draw on that, but drawing directly on the Frame is also possible and -in this case- 1 byte shorter ¯\_(ツ)_/¯).
And finally we add the text, for which no calculations are used. In the used Font the letters aren't monospace (W is for example larger than S), and in Java everything is drawn from the top-left \$x,y\$-coordinate, so we can't really make any smart calculations here tbh. I've just added some temporary red lines going beyond the points and manually adjusted the text positions a bit:
If you think they aren't correct, they can be moved slightly by adjusting the coordinates, without changing the byte-count.
For those curious, here are the adjustments made to the coordinates of the tips to position the texts:
\$N=300-11, 80\$
\$E=550+3,330+11\$
\$S=275+15,580+25\$
\$W=50-30,330+11\$
\$NE=441-7,188-2\$
\$SE=441-4,471+25\$
\$SW=158-38,471+27\$
\$NW=158-37,188-2\$
And well, that's it. Thank you for listening to my TED talk about drawing a compass in Java. :)