7
\$\begingroup\$

You want to draw a regular polygon but you have limited space! In this challenge, you should draw a polygon with n sides which is as big as possible for a given square container image.

I found surprisingly little information on the Internet about inscribing a polygon into a square. To save you the hassle, I verified that in almost all cases one of the vertices is on the diagonal of the square. The diagram below marks the center of the polygon and some important segments. One exception is when n in divisible by 8: then the maximal polygon has 4 sides parallel to the sides of the square.

maximal polygon inscribed in square

If you want to skip the math, here are the lengths of the blue and magenta segments:

formulas where ⌊x⌉ means x rounded to nearest integer

These formulas are only correct for n not divisible by 8; when it's divisible by 8, the math is much easier (an exercise for the reader).

Input: a number n in the range 3...16 inclusive.

Output: a square image with a maximal regular n-gon

  • Draw just the boundary of the polygon or fill it - whatever is easier
  • The dimensions of the output image should be the same for all n
  • Width of the image should be exactly equal to height; alternatively, make a rectangular image, but then also draw the containing square
  • The regular polygon must be the biggest one that can fit in the image or in containing square
  • Any orientation
  • If you make a raster image, the dimensions of the containing square must be at least 200 pixels

Examples (using different styles but you should pick one):

3: triangle

7: heptagon (with bounding rectangle)

12: 12-gon (with bounding rectangle of same colour)

16: 16-gon (filled)

\$\endgroup\$
1
  • \$\begingroup\$ It took me a while to undetstand the formulas for B and M. Looks like B and M (without the scale factor 1/S) give the cosines of a couple of points on the unit circle; the rounded parts give the indices two of the points touching the square (starting at 0 for the one on the diagonal; and the sum B+M (without the scale factor) gives the width of the square in relation to the unit circle (reflecting one of the points in the green diagonal shows that they should be added.) It's important to note that B and M can be different; the centre of the polygon is not necessarily the centre of the square. \$\endgroup\$ Dec 26, 2023 at 0:57

3 Answers 3

3
\$\begingroup\$

R, 124 bytes

\(n)plot(rbind(p<-cbind(cos(t<-(1:n/n+1/8+(!n%%8)/2/n)*2*pi),sin(t)),p[1,]),t="l",ann=F,xaxt="n",yaxt="n",xaxs="i",yaxs="i")

Attempt This Online! - no graphical output

A function taking a single argument \$n\$ and plotting a polygon with \$n\$ sides circumscribed by a square. If \$n \bmod 8 ≠ 0\$ then one of the polygon’s points will be at 45°; otherwise one of them will be at 360/2n°. The points are then calculated using sin and cos. R’s plot function will plot the bounding square and maximise the polygon to that square. The rest of the code is just ensuring there’s nothing additional plotted like axes titles and ticks.

Thanks to @pajonk for saving a byte!

\$\endgroup\$
2
  • \$\begingroup\$ @LevelRiverSt yes, my mistake. Should be fixed now \$\endgroup\$ Dec 27, 2023 at 2:43
  • 1
    \$\begingroup\$ I think an unnecessary newline slipped in. \$\endgroup\$
    – pajonk
    Dec 27, 2023 at 9:03
2
\$\begingroup\$

JavaScript (ES2019), 216 bytes

f=
n=>`<svg xmlns="http://www.w3.org/2000/svg" viewBox="${[l=(M=Math).min(...b=(a=[...Array(n)].map((_,i)=>[M.sin(w=((i*2+!(n%8))/n+.25)*M.PI),M.cos(w)])).flat()),l,l=M.max(...b)-l,l]}"><path d="M${a.join`L`}Z"/></svg>`
html{height:100%;display:flex;}body{display:flex;flex-direction:column;align-items:start;}img{flex:1;}
<input type=number min=3 max=16 oninput=o.src="data:image/svg+xml,"+f(+this.value)><img id=o>

The function, here assigned to f for convenience of the test snippet, outputs an SVG of the polygon filled in black, which the test snippet converts to a data: URL so that it can set it as the source of the image.

\$\endgroup\$
0
\$\begingroup\$

LOGO, 195 192 bytes

TO p :n
make "u 0make "v .1 pu
for[i 0 32][make "a(:i*2+not :n%8)*180/:n+45make "x cos(:a)if :x<:u[make "u :x]if :x-:u>:v [make "v :x-:u]if :i>15[pd]setxy (:x-:u)*99/:v ((sin :a)-:u)*99/:v]END

Run at https://www.calormen.com/jslogo/

Call the procedure like this: p 16

Recommended to do cs p 4 to clear the screen and draw a bounding box. ht and st hide and show the turtle.

The loop starts with a pu to lift the pen up and always iterates 32 times. This ensures the correct minumum and maximum values of x = cos a are contained in u and v. After 16 iterations the pen is put down with pd and the polygon is drawn at the correct scale.

\$\endgroup\$

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Not the answer you're looking for? Browse other questions tagged or ask your own question.