11
$\begingroup$

A zonogon is a polygon that is convex and is made only out of pairs of parallel sides with the same length. Any regular polygon with an even number of sides is an example of a zonogon.

When I use: Graphics[RandomPolygon[{"StarShaped", 10}]], I get something like this: random Star-Shaped Decagon

When I use: Graphics[RandomPolygon[{"Convex",6}]], I get something like this: random convex hexagon

And for regular polygons, we can do something different with: Graphics[RegularPolygon[{randomPositiveReal, randomAngle}, randomInteger]].

But unfortunately there is no option for zonogons. The code: Graphics[RandomPolygon[{"Zonogon",6}]] gives an error.

I found this gives a random hexagon that is a zonogon before a random rotation:

height=500;
width=500;
X6={};AppendTo[X6,RandomReal[{0,width}]];AppendTo[X6,RandomReal[{0,height}]];
X3={};AppendTo[X3,RandomReal[{X6[[1]],width}]];AppendTo[X3,X6[[2]]];
X1={};AppendTo[X1,RandomReal[{X6[[1]],X3[[1]]}]];AppendTo[X1,RandomReal[{0,X3[[2]]}]];
X2={};AppendTo[X2,RandomReal[{X1[[1]],X3[[1]]}]];AppendTo[X2,X1[[2]]];
X4={};X4=X3+X6-X1;
X5={};X5=X3+X6-X2;
ListLinePlot[{X1,X2,X3,X4,X5,X6,X1},Axes->False]

Which gives something like this:

random hexagon that is also a zonogon

When I look at more examples of zonogons here, I noticed that I believe zonogons can be made by 'stretching' parallel sides of a regular polygon.

How can I do this to make a random zonogon in Mathematica?

$\endgroup$

4 Answers 4

10
$\begingroup$

You can get some shapes with AffineTransform and Rotate. Define:

zonogon[n_]:=
Rotate[GeometricTransformation[Rotate[RegularPolygon[n],RandomReal[2Pi]],
AffineTransform[RandomReal[1,{2,2}]]],RandomReal[2Pi]]

Then generate a few:

Table[Graphics[zonogon[RandomChoice[Range[4, 14, 2]]]], 10]

enter image description here

$\endgroup$
1
  • $\begingroup$ When I check it, it seems like it never collapses to having fewer sides than it is supposed to. Also, I learned what an affine transformation is. I didn't know the word for that concept before today. Thank you. $\endgroup$
    – Teg Louis
    Commented Jul 21, 2023 at 22:56
19
$\begingroup$

We can using Minkowski Sum (RegionDilation) of any Line's from the fixed point p.

  • For 3D.
p = {0, 0, 0};
n = 10;
lines = Table[Line[{p, p + RandomReal[{-5, 5}, 3]}], n];
polyhedron = Fold[RegionDilation, lines];
HighlightMesh[polyhedron, {Style[1, White], Style[2, Darker@Cyan]}, 
 ViewProjection -> "Orthographic"]

enter image description here

  • For 2D.
p = {0, 0};
n = 4;
lines = Table[Line[{p, p + RandomReal[{-5, 5}, 2]}], n];
poly = Fold[RegionDilation, lines];
Graphics[{FaceForm[Darker@Cyan], EdgeForm[Thick], poly, Thick, 
  Orange, lines /. Line -> Arrow, White, AbsolutePointSize[10], 
  Point[p]}]

enter image description here

  • For 2D,we demonstrate the process of the Region Dilation.After that, we want to subdivide the region into some Parallelograms.
SeedRandom[1111];
p = {0, 0};
n = 9;
dirs = RandomPoint[Circle[{0, 0}, 1, {-(π/2), π/2}], n];
lines = Line[{p, p + #}] & /@ dirs;
polys = FoldList[RegionDilation, lines];
parts = Most@MapThread[RegionDifference, {Rest@polys, Most@polys}];
Graphics[{EdgeForm[{Thick, White}], FaceForm@RandomColor[], #} & /@ 
  parts]

enter image description here

  • One way to subdivede the zonogon into Parallelograms.
SeedRandom[1];
p = {0, 0};
n = 11;
dirs = RandomPoint[Circle[{0, 0}, 1], n];
lines = Line[{p, p + #}] & /@ dirs;
polys = FoldList[RegionDilation, lines];
parts = Most@MapThread[RegionDifference, {Rest@polys, Most@polys}];
pts = MapThread[
    Complement, {Rest[First /@ polys], Most[First /@ polys]}][[2 ;; 
     n - 2]];
Animate[Graphics[{MapIndexed[{ColorData[97][First@#2], #1} &, parts], 
   Arrowheads[.025], White, 
   Take[MapThread[
     Arrow /@ Thread[{#1 - Threaded@#2, #1}] &, {pts, 
      dirs[[3 ;; n - 1]]}], i]}], {i, 1, n - 3, 1}, AnimationRate -> 1]

enter image description here

  • By lifting the 2D data to 3D, we can found that subdivede the zonogon into Parallelograms is not unique.
SeedRandom[1];
p = {0, 0};
n = 11;
dirs = RandomPoint[Circle[{0, 0}, 1], n];
 pic = 
 Graphics3D[
  Fold[RegionDilation, 
   Line[{{0, 0, 0}, {0, 0, 0} + #}] & /@ (PadRight[#, 3] & /@ dirs)], 
  ViewPoint -> Top, 
  ViewProjection -> "Orthographic"]; SeedRandom[]; 
pics = 
 Table[Graphics3D[
   Fold[RegionDilation, 
    Line[{{0, 0, 0}, {0, 0, 0} + #}] & /@ 
     MapThread[Append, {dirs, RandomReal[{0, 1}, n]}]], 
   ViewPoint -> Top, ViewProjection -> "Orthographic"], 
  4]; 
GraphicsRow[{pic, pics} // Flatten]

enter image description here

Edit

  • To subdivide the 2D case to varies several Parallelograms is still not so easy. Here we only provided one possible way. I think if we can find the way to change the hexagons in the figure, we will get many subdivides.
k = 7;
es = RandomReal[{0, 1}, k]*
   SortBy[RandomPoint[Circle[{0, 0}, 1, {0, π}], k], 
    VectorAngle[{1, 0}, #] &];
level[j_] := 
  MapThread[
   Polygon[Join[#1, Reverse@#2]] &, {Partition[#, 2, 1] &@
     FoldList[Plus, Take[es, -j]], 
    Partition[#, 2, 1] &@
     Prepend[FoldList[Plus, Take[es, -j + 1]], {0, 0}]}];
Graphics[
 Table[{FaceForm[ColorData[97][j]], EdgeForm[{White, Thick}], 
   level[j]}, {j, 1, k}]]

enter image description here

Clear[k, es, level];
k = 13;
es = AngleVector /@ Table[-(π/(2 k)) + j*π/k, {j, 1, k}];
es = CirclePoints[{1, π + π/(2 k)}, 2 k];
level[j_] := 
  MapThread[
   Polygon[Join[#1, Reverse@#2]] &, {Partition[#, 2, 1] &@
     FoldList[Plus, Take[es, -j]], 
    Partition[#, 2, 1] &@
     Prepend[FoldList[Plus, Take[es, -j + 1]], {0, 0}]}];
Graphics[
 Table[{FaceForm[ColorData[97][j]], EdgeForm[{White, Thick}], 
   level[j]}, {j, 1, k}]]

enter image description here

  • Transpose the data to get the same pattern of colors.
lear[k, es, level];
k = 13;
es = CirclePoints[{1, π + π/(2 k)}, 2 k];
level[j_] := 
  MapThread[
   Polygon[Join[#1, Reverse@#2]] &, {Partition[#, 2, 1] &@
     FoldList[Plus, Take[es, -j]], 
    Partition[#, 2, 1] &@
     Prepend[FoldList[Plus, Take[es, -j + 1]], {0, 0}]}];
polys = Flatten[Table[level[j], {j, 1, k}], {{2}, {1}}];
Graphics[
 Table[{FaceForm[ColorData[97][i]], EdgeForm[{Thick, White}], 
   polys[[i]]}, {i, 1, k - 1}]]

enter image description here

a mathematical conjecture

It seems that every "StarShaped" can be extend to a unique "Convex" by extend Parallelogram.(the code need to be improved) enter image description here

And every "StarShaped" which construct by Parallelograms can be extend to a unique "Zonogon".

enter image description here

$\endgroup$
6
  • $\begingroup$ What does $n$ mean for the 3D case? $\endgroup$
    – Teg Louis
    Commented Jul 21, 2023 at 22:53
  • 1
    $\begingroup$ @TegLouis n is the numbers of the lines from the point p. $\endgroup$
    – cvgmt
    Commented Jul 21, 2023 at 23:55
  • $\begingroup$ I don't have a proof, but think a zonogon is a projection of a cylinder with zonogon end caps. Here is an example for hexagons that are also zonogons being a projection of a cuboid. I don't know if this holds for breaking the 2D case into parallelograms. $\endgroup$
    – Teg Louis
    Commented Jul 25, 2023 at 16:15
  • $\begingroup$ Also, your solution is the coolest looking one. Zonogons are so cool and important, but I was stunned to only find 96 papers about them on Google Scholar, and a large percentage were just exposé's of repetitive information. $\endgroup$
    – Teg Louis
    Commented Jul 25, 2023 at 16:19
  • 1
    $\begingroup$ How can I download anamination file? $\endgroup$ Commented Jul 30, 2023 at 13:31
9
$\begingroup$

You can start with a regular 2n polygon that has 2 sides parallel to the x axis. Then stretch the polygon along the x axis. Afterwards, you rotate the polygon so that the next side is parallel to the x axis and stretch again. After you did this n times, you have your zonogon.

n = 3;
pts = CirclePoints[2 n];
Do[
  add = RandomReal[1];
  pts[[;; n]] = (# + {add, 0}) & /@ pts[[;; n]];
  pts[[n + 1 ;;]] =  (# - {add, 0}) & /@ pts[[n + 1 ;;]];
  pts = RotateRight[pts];
  , {n}];
AppendTo[pts, pts[[1]]];
Graphics[Line[pts], Axes -> True]

enter image description here

$\endgroup$
1
  • $\begingroup$ I think your solution is the best so far that demonstrates mathematically what goes under the hood. It is very concise. $\endgroup$
    – Teg Louis
    Commented Jul 21, 2023 at 23:40
6
$\begingroup$

A much cheaper way is by just creating directions and line pieces and assembling (over the much more expansive Minkowski sum/RegionDilation), and much more random than the stretched regular polygons:

ClearAll[CreateRandomZonogon]
CreateRandomZonogon[sides_?EvenQ, lendist : {min_, max_}] := 
 Module[{m, angles, dirs, lengths},
  m = sides/2;
  angles = RandomReal[{0, 1}, m];
  angles /= Total[angles]/(Pi);
  angles = Join[angles, angles];
  dirs = Accumulate[angles];
  dirs += RandomReal[{0, 2 Pi}];
  lengths = RandomReal[lendist, m];
  lengths = Join[lengths, lengths];
  Polygon[Accumulate[MapThread[AngleVector[{#1, #2}] &, {lengths, dirs}]]]
  ]
CreateRandomZonogon[8, {0.5, 1}] // Graphics

here the first argument is the number of sides (should be even). And then the second specification is the range of lengths for the sides, which i set to 0.5 to 1, but can be anything (positive).

$\endgroup$
2
  • 1
    $\begingroup$ Also, yours is probably the best one so far for generalizing and abstracting to solve related mathematics problems. And it is extremely readable and customizable. $\endgroup$
    – Teg Louis
    Commented Jul 24, 2023 at 20:04
  • 1
    $\begingroup$ The question: How to creatively create a random belt polygon or belt polyhedron? is a generalization of this question. It used your solution. I am not 100% sure it always makes a belt polygon though. $\endgroup$
    – Teg Louis
    Commented Aug 4, 2023 at 2:16

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.