15
\$\begingroup\$

Related: Draw A Reuleaux Triangle!, Draw a regular polygon

A Reuleaux polygon is a curve of constant width made up of circular arcs of constant radius. The most well-known Reuleaux polygon is the Reuleaux triangle, which has three sides1. In this challenge, you will be tasked to draw a regular Reuleaux polygon of a given number of sides.

A Reuleaux polygon is constructed by taking a polygon and replacing each of its sides with an arc centered at the opposite vertex.

This sort of shape can only be constructed from a polygon with an odd number of sides, so your input will be an odd number greater than or equal to three.

Reuleaux triangle (3 sides) Reuleaux pentagon (5 sides) Reuleaux heptagon (7 sides)
constructed triangle constructed pentagon constructed heptagon
triangle pentagon heptagon

The circles in the first row are shown to demonstrate the construction; Your program's output should be closer to that of the second row (though the center mark is optional.)

Given an odd number ≥ 3 and, optionally, an arc radius, draw a regular Reuleaux polygon with that many sides. If you do not take an arc radius as input, ensure that the image is at a high enough resolution that the curves can be deciphered.

This is ; the shortest solution in each language wins.


1 A curve can't have "sides" by the standard definition where each side is a line, but for the purposes of this task I am using the term "side" everywhere for simplicity.
\$\endgroup\$
2
  • \$\begingroup\$ If the axes do not show the scale, arc radius is irrelevant. Can we choose not to take the arc radius as input? \$\endgroup\$
    – Luis Mendo
    Commented Jul 12 at 12:25
  • 2
    \$\begingroup\$ Yeah, sure, I only really said that requirement to make sure all solutions work at a good enough resolution that you can decipher the curves, but I'll remove the requirement and rephrase 👍 \$\endgroup\$ Commented Jul 12 at 12:43

9 Answers 9

6
\$\begingroup\$

Python, 64 bytes

from turtle import*
def f(n,d):
 for c in[0,d]*n:circle(c,180/n)

ATO Does not work for this (missing _tkinter)! Nor does TIO.

History: 80,82,64.

How?

Observing that the arc lengths always sum to half a full circle we let the turtle draw a circle omitting every other of a total of \$2n\$ equal length arcs

\$\endgroup\$
4
  • \$\begingroup\$ f(7,40) doesn't seem to draw the full shape: PythonSandbox Turtle Editor \$\endgroup\$ Commented Jul 11 at 21:11
  • \$\begingroup\$ @noodleperson you sure that isn't Python 2 or something? Forcing floats where there are divisions seems to fix it. Also, it runs just fine on my computer. \$\endgroup\$ Commented Jul 11 at 22:02
  • \$\begingroup\$ I trust you, it might be Python 2 \$\endgroup\$ Commented Jul 11 at 22:10
  • \$\begingroup\$ @Albert.Lang It's true. Changing the code to ensure it's a float works. Updated version \$\endgroup\$
    – mbomb007
    Commented Jul 12 at 14:21
5
\$\begingroup\$

Wolfram Language (Mathematica), 62 bytes

Graphics[ResourceFunction["ReuleauxPolygon"][Input[],Input[]]]

Of course Wolfram has a way to do this. First input is arc radius, and second is \$n\$ number of sides.


Example with input 100, 5:

enter image description here

\$\endgroup\$
2
  • \$\begingroup\$ Could this be made shorter as a function? Something like Graphics[ResourceFunction["ReuleauxPolygon"][#1,#2]&, maybe? I'm not certain on Mathematica's syntax so idk if this actually works. \$\endgroup\$ Commented Jul 14 at 4:05
  • \$\begingroup\$ @ConorO'Brien Maybe! This challenge was the first time I ever tried anything in Wolfram, so your guess is as good as mine. \$\endgroup\$
    – SanguineL
    Commented Jul 15 at 14:09
4
\$\begingroup\$

Ruby, 152 142 138 bytes

->n{s='<svg viewBox="-50-9 99 18"><path d="M9 0'
n.times{|j|s<<"A#{r=9/(k=1i**(1.0/n)).imag} #{r} 0 0,0 %f %f"%(9*k**(4*~j)).rect}
s+'">'}

Try it online!

A function returning a string containing an SVG image such as the one below. The n points always fall on a circle of radius 9. The radius of curvature of the sides varies according to the value of n.

<svg viewBox="-50-9 99 18"><path d="M9 0A18.000000000000004 18.000000000000004 0 0,0 -4.500000 -7.794229A18.000000000000004 18.000000000000004 0 0,0 -4.500000 7.794229A18.000000000000004 18.000000000000004 0 0,0 9.000000 0.000000">

Viewing notes

The SVG has been tested in Chrome and Edge. A concern has been raised about the lack of space between the two -50s defining coordinates of the corner of the viewbox, but that makes no difference to the output in either of these browsers.

There is an issue with the browsers sizing the viewbox based on the width only and ignoring the height, requiring the user to scroll vertically. It is recommended to hit Run code snippet before expanding, to avoid getting a horizontally wide but vertically very short window requiring excessive scrolling. Narrowing the browser window helps with this.

I have reduced the radius of the output from 40 units to 9 units to make it easier to get the whole Reuleaux polygon into view (this also saves 3 bytes.) I have also reduced the height of the viewbox to help eliminate vertical scrolling (this saves another byte.)

\$\endgroup\$
7
  • \$\begingroup\$ The value of the viewBox attribute is a list of four numbers <min-x>, <min-y>, <width> and <height>, separated by whitespace and/or a comma. Please could you add one in between the first two numbers. \$\endgroup\$
    – Neil
    Commented Jul 11 at 23:39
  • \$\begingroup\$ "Given a odd number ≥ 3 and an arc radius" - does this code implement a choice of arc radius? \$\endgroup\$ Commented Jul 12 at 9:51
  • \$\begingroup\$ @DominicvanEssen I removed that requirement because it didn't seem to add to the task. \$\endgroup\$ Commented Jul 12 at 12:46
  • \$\begingroup\$ @noodleperson Thanks, I didn't actually notice that requirement until Dominic mentioned it, and when I got round to doing something about I found you had deleted it. \$\endgroup\$ Commented Jul 12 at 16:41
  • 1
    \$\begingroup\$ It doesn't render in my standards-compliant SVG viewer which is why I complained. Please specify the needed SVG viewer as part of your answer. \$\endgroup\$
    – Neil
    Commented Jul 12 at 18:51
3
\$\begingroup\$

R, 116 111 98 bytes

Edit: no longer requiring radius to be given as an input saves 13 bytes.

\(n,i=1:396/99-2,v=1i^(1:n*4/n),R=abs(1-v[n/2]),`~`=sapply)image(i~\(x)i~\(y)all(abs(x+y*1i-v)<R))

Try it at rdrr.io. (note that rdrr.io runs on an earlier version of R that does not use the \ syntax for a function definition, so the code in the link is 21 bytes longer)

enter image description here

\$\endgroup\$
5
  • \$\begingroup\$ I think you left the definition of R from previous versions and you can omit it now. \$\endgroup\$
    – pajonk
    Commented Jul 12 at 17:04
  • \$\begingroup\$ Also, using outer and Vectorize saves further 3 bytes, if the output is allowed to be rotated: function(n,v=1i^(1:n*4/n))image(outer(i<-1:396/99-2,i,Vectorize(function(x,y)all(abs(x+y*1i-v)<abs(1-v[n/2]))))) \$\endgroup\$
    – pajonk
    Commented Jul 12 at 18:26
  • 1
    \$\begingroup\$ @pajonk - I actually golfed this for \, since ≥4.1 is 'normal' for R now, but realised that it still doesn't run on rdrr.io, which (I think) is the only online environment with graphical output. Please consider 98 bytes with \ my real attempt, even if I can't provide an online-runnable link... \$\endgroup\$ Commented Jul 12 at 18:38
  • 1
    \$\begingroup\$ Anyway, my first comment still holds :) \$\endgroup\$
    – pajonk
    Commented Jul 12 at 18:57
  • \$\begingroup\$ @pajonk You're right. I think fixed now. \$\endgroup\$ Commented Jul 12 at 19:06
3
\$\begingroup\$

MATL, 36 bytes

t:!=ZFt9W:8W/qt!J*+le-|wq|X>>a[]e0YG

Try at MATL Online!

For input n, this computes the n-th roots of unity, and colours each pixel if and only if it is at a distance D or less from all roots, where D is the maximum distance between pairs of roots.

The code uses this trick (adapted to MATL) to compute the roots of unity.

t      % Implicitly take input: n. Duplicate
:!     % Range, transpose. Gives the column vector [1; 2; ...; n]
=      % Equal? element-wise. Gives [0; 0; ...; 1]
ZF     % FFT. Gives roots of unity (*)
t      % Duplicate
9W:    % 2^9, range. Gives the row vector [0, 1, ..., 512]
8W/    % Divide each ech entry by 2^8
q      % Subtract 1. Gives [-0.99609375, -0.9921875, ..., 1]
t!J*   % Duplicate, transpose, multiply element-wise by imaginart unit
+      % Add element-wise with broadcast. Gives a 512×512 complex grid ranging
       % from -0.99609375 to 1 on each axis
le     % Linearize (in column-major order) to a row vector of length 512^2 (**)
-|     % Absolute difference between (*) and (**), element-wise with broadcast.
       % Gives an n×512^2 distance matrix
w      % Swap. Moves original copy of (*) to the top
q|X>   % Subtract 1, absolute value, maximum. Gives distance D
>      % Greater than? element-wise. Gives an n×512^2 logical matrix
a      % Any. Gives a row vector of length 512^2, containing 1 if the pixel
       % is at a distance greater than D from at least one circle center, and
       % 0 otherwise
[]e    % Reshape as a square (512×512) matrix
0YG    % Write as image file. Implicitly display
\$\endgroup\$
2
\$\begingroup\$

Logo, 61 60 bytes

to r:n
repeat:n[pd arc 90 180/:n pu fd 90 rt 180-180/:n]
end

Unfortunately the online logo resource I used to use is no longer available, but you can paste the code into the textbox on https://rmmh.github.io/papert/static/ and run it. (Also paste the following code to actually get anything to run.)

clear
r 5

(Substitute your desired value for 5.)

It's also possible to draw a padded polygon; this is still a curve of constant width but that with w is now d+2p where p is the extra padding:

to r:n:d:p
repeat:n[pd arc:p 180/:n lt 180 arc:d+:p 180/:n pu fd:d lt 180/:n]
end

clear
r 5 100 25
\$\endgroup\$
2
\$\begingroup\$

Scratch 3.23.1, 160 145 bytes

  • thanks to noodle person for syntax correction & golfing
when gf clicked
erase all
pen down
ask()and wait
repeat(answer
turn cw((180)/(answer))degrees
repeat((180)/(answer
move(3)steps
turn cw(1)degrees

A program that inputs \$n\$ - a number of sides and plots a Reuleux polygon of \$n\$ sides. Radius length is fixed.

enter image description here

\$\endgroup\$
3
  • 1
    \$\begingroup\$ Nice solution! You should use ScratchBlocks syntax to calculate your byte-count, and you must have a when gf clicked block or define block. If you use a define block it must work more than once, but with when gf clicked it only has to work when you start the program, so you can omit the go to, point in direction, and erase all blocks because you can assume that's the initial state of the stage. Finally, it's a bit shorter to skip the set[n v]to(answer and just use answer. With these changes made, your solution is 139 bytes: tinyurl.com/bdeh3zwb \$\endgroup\$ Commented Jul 13 at 12:17
  • \$\begingroup\$ Actually it can be a bit shorter than my suggestion, and after experimenting I think you do need the erase all after all. 145 bytes: scratchblocks.github.io/… \$\endgroup\$ Commented Jul 13 at 12:23
  • \$\begingroup\$ @noodleperson, thanks, I didn't know there is a translation available of Scratch blocks into text. \$\endgroup\$ Commented Jul 13 at 13:58
2
\$\begingroup\$

Javascript, 154 147 143 bytes

A function returning a string containing an SVG for inline insertion into a HTML page.

2 bytes less due to changed count.
5 byte saved thx to hints by @noodle person and @Neil.
4 bytes saved by using eval("with(Math)for..., thx to @noodle person.

f=
n=>`<svg viewBox=-4,-1,9,2><path d=M${eval("with(Math)for(i=s=0;i<n;i++)s+=[sin(a=2*i*PI/n),cos(a)]+'A'+[r=(2+2*cos(PI/n))**.5,r,0,0,0]")}0,1>`
<input type=number size=2 min=3 step=2 oninput=w.setHTMLUnsafe(f(value|0))><div id=w>

Ungolfed

f = n => {
  s = '<svg viewBox=-4,-1,9,2><path d=M'
  for(i=s=0;i<n;i++) {
    a = 2 * i * Math.PI / n
    p = [Math.sin(a), Math.cos(a)]
    r = (2 + 2 * Math.cos(Math.PI / n)) ** 0.5
    s += p + 'A' + [r,r,0,0,0]
  }
  return s += '0,1>'
}
\$\endgroup\$
6
  • \$\begingroup\$ It's two bytes shorter to define b (and M) inside the Array(n) call by doing Array(n,b=(M=Math).PI/n), because that way you can drop the parentheses around the whole expression. Also, because f isn't recursive and doesn't reference its own name, you can omit the f= part from your submission score. \$\endgroup\$ Commented Jul 13 at 1:38
  • \$\begingroup\$ @noodleperson no, Array(n,b=(M=Math).PI/n) would be an Array with two values instead of n values. \$\endgroup\$
    – ccprog
    Commented Jul 13 at 1:42
  • \$\begingroup\$ Ah, my mistake. You could still do /* ... */ (_,i)=>[(M=Math).sin(a=2*i*M.PI/n) /*...*/ r=(2+2*M.cos(M.PI/n) /* ... */ and drop parens which saves one byte \$\endgroup\$ Commented Jul 13 at 1:48
  • 1
    \$\begingroup\$ You don't need to include f= in your byte count because the function isn't recursive (I normally put the f= on the previous line in that case to make it clearer). Array.from(Array(n),(_,i) can be [...Array(n)].map((_,i). ,r]+',0,00') can be ,r,0,0,0]). \$\endgroup\$
    – Neil
    Commented Jul 13 at 9:19
  • \$\begingroup\$ Using with(Math) and a for loop inside eval is one byte shorter, for 146: n=>`<svg viewBox=-4,-1,9,2><path d=M${eval("with(Math)for(i=s=0;i<n;i++)s+=[sin(a=2*i*PI/n),cos(a)]+'A'+[r=sqrt(2+2*cos(PI/n)),r,0,0,0,'']")}0,1>` \$\endgroup\$ Commented Jul 13 at 16:37
1
\$\begingroup\$

APL(Dyalog Unicode), 58 56 bytes SBCS

-2 bytes due to unused variable assignment B←.

A dfn that takes the number of edges and outputs a bitmap of the shape.

{(C-C⊖⍨⌈⍵÷2)∧.>⍥|C∘.-I∘.+0J1×I←40÷⍨¯41+⍳81⊣C←¯1*⍵÷⍨+⍨⍳⍵}

It uses complex numbers to encode points on the 2D plane.

{(C-C⊖⍨⌈⍵÷2)∧.>⍥|C∘.-I∘.+0J1×I←40÷⍨¯41+⍳81⊣C←¯1*⍵÷⍨+⍨⍳⍵}
                                           C←¯1*⍵÷⍨+⍨⍳⍵  ⍝ vertces
                     I∘.+0J1×I←40÷⍨¯41+⍳81               ⍝ points on the plane
                 C∘.-                                    ⍝ displacement vectors to the vertices
 (C-C⊖⍨⌈⍵÷2)                                             ⍝ displacement vectors between oppisite vertices
            ∧.>⍥|                                        ⍝ are the points within the reuleaux polygon

Try it on APLgolf!

\$\endgroup\$
0

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.