001/*
002 * Renderer Models. The MIT License.
003 * Copyright (c) 2022 rlkraft@pnw.edu
004 * See LICENSE for details.
005*/
006
007package renderer.models_L;
008
009import renderer.scene.*;
010import renderer.scene.primitives.*;
011import renderer.scene.util.MeshMaker;
012
013/**
014   Create a wireframe model of a regular tetrahedron
015   with its center at the origin, having edge length
016   {@code 2*sqrt(2)}, and with its vertices at corners
017   of the cube with vertices {@code (±1, ±1, ±1)}.
018<p>
019   See <a href="https://en.wikipedia.org/wiki/Tetrahedron" target="_top">
020                https://en.wikipedia.org/wiki/Tetrahedron</a>
021
022   @see Cube
023   @see Octahedron
024   @see Icosahedron
025   @see Dodecahedron
026*/
027public class Tetrahedron extends Model implements MeshMaker
028{
029   public final int n1;
030   public final int n2;
031   public final boolean useTwoParameterConstructor;
032
033   /**
034      Create a regular tetrahedron with its center at
035      the origin, having edge length {@code 2*sqrt(2)},
036      and with its vertices at corners of the cube with
037      vertices {@code (±1, ±1, ±1)}.
038   */
039   public Tetrahedron()
040   {
041      this(false);
042   }
043
044
045   /**
046      Create a regular tetrahedron or its dual tetrahedron
047      (the dual of a tetrahedron is another tetrahedron).
048   <p>
049      <a href="https://en.wikipedia.org/wiki/Tetrahedron#Regular_tetrahedron" target="_top">
050               https://en.wikipedia.org/wiki/Tetrahedron#Regular_tetrahedron</a>
051   <p>
052      The combination of these two dual tetrahedrons is a stellated octahedron.
053   <p>
054      <a href="https://en.wikipedia.org/wiki/Stellated_octahedron" target="_top">
055               https://en.wikipedia.org/wiki/Stellated_octahedron</a>
056
057      @param dual  choose between the two dual tetrahedrons
058   */
059   public Tetrahedron(final boolean dual)
060   {
061      super("Tetrahedron");
062
063      this.n1 = 0;
064      this.n2 = 0;
065      useTwoParameterConstructor = true;
066
067      // Create the tetrahedron's geometry.
068      // It has 4 vertices and 6 edges.
069      if (! dual)
070      {
071         addVertex(new Vertex( 1,  1,  1),
072                   new Vertex(-1,  1, -1),
073                   new Vertex( 1, -1, -1),
074                   new Vertex(-1, -1,  1));
075      }
076      else // Create the dual tetrahedron by
077      {    // inverting the coordinates given above.
078         addVertex(new Vertex(-1, -1, -1),
079                   new Vertex( 1, -1,  1),
080                   new Vertex(-1,  1,  1),
081                   new Vertex( 1,  1, -1));
082      }
083
084      addPrimitive(new LineSegment(0, 1),  //top (bottom) edge
085                   new LineSegment(2, 3),  //bottom (top) edge
086                   new LineSegment(0, 2),
087                   new LineSegment(0, 3),
088                   new LineSegment(1, 2),
089                   new LineSegment(1, 3));
090   }
091
092
093   /**
094      Create a regular tetrahedron with its center at
095      the origin, having edge length {@code 2*sqrt(2)},
096      and with its vertices at corners of the cube with
097      vertices {@code (±1, ±1, ±1)}.
098      <p>
099      Add line segments fanning out from each vertex to
100      its opposite edge.
101
102      @param n1 number of lines fanning out from v0 and v1 towards the edge (v2, v3)
103      @param n2 number of lines fanning out from v2 and v3 towards the edge (v0, v1)
104      @throws IllegalArgumentException if {@code n1} is less than 0
105      @throws IllegalArgumentException if {@code n2} is less than 0
106   */
107   public Tetrahedron(final int n1, final int n2)
108   {
109      super(String.format("Tetrahedron(%d,%d)", n1, n2));
110
111      if (n1 < 0)
112         throw new IllegalArgumentException("n1 must be greater than or equal to 0");
113      if (n2 < 0)
114         throw new IllegalArgumentException("n2 must be greater than or equal to 0");
115
116      this.n1 = n1;
117      this.n2 = n2;
118      useTwoParameterConstructor = true;
119
120      // Create the tetrahedron's geometry.
121      // It has 4 vertices and 6 edges.
122      final Vertex v0 = new Vertex( 1,  1,  1),
123                   v1 = new Vertex(-1,  1, -1),
124                   v2 = new Vertex( 1, -1, -1),
125                   v3 = new Vertex(-1, -1,  1);
126
127      addVertex(v0, v1, v2, v3);
128
129      addPrimitive(new LineSegment(0, 1),  //top (bottom) edge
130                   new LineSegment(2, 3),  //bottom (top) edge
131                   new LineSegment(0, 2),
132                   new LineSegment(0, 3),
133                   new LineSegment(1, 2),
134                   new LineSegment(1, 3));
135
136      fan(n1, 0, v2, v3); // fan out from v0
137      fan(n1, 1, v2, v3); // fan out from v1
138      fan(n2, 2, v0, v1); // fan out from v2
139      fan(n2, 3, v0, v1); // fan out from v3
140   }
141
142
143   /**
144      Create a regular tetrahedron with its center at
145      the origin, having edge length {@code 2*sqrt(2)},
146      and with its vertices at corners of the cube with
147      vertices {@code (±1, ±1, ±1)}.
148      <p>
149      Add line segments fanning out from each vertex onto
150      its three adjacent sides.
151
152      @param m0 number of lines fanning out from v0 onto each adjacent side of the tetrahedron
153      @param m1 number of lines fanning out from v1 onto each adjacent side of the tetrahedron
154      @param m2 number of lines fanning out from v2 onto each adjacent side of the tetrahedron
155      @param m3 number of lines fanning out from v3 onto each adjacent side of the tetrahedron
156      @throws IllegalArgumentException if {@code m0} is less than 0
157      @throws IllegalArgumentException if {@code m1} is less than 0
158      @throws IllegalArgumentException if {@code m2} is less than 0
159      @throws IllegalArgumentException if {@code m3} is less than 0
160   */
161   public Tetrahedron(final int m0, final int m1, final int m2, final int m3)
162   {
163      super(String.format("Tetrahedron(%d,%d,%d,%d)", m0, m1, m2, m3));
164
165      if (m0 < 0)
166         throw new IllegalArgumentException("m0 must be greater than or equal to 0");
167      if (m1 < 0)
168         throw new IllegalArgumentException("m1 must be greater than or equal to 0");
169      if (m2 < 0)
170         throw new IllegalArgumentException("m2 must be greater than or equal to 0");
171      if (m3 < 0)
172         throw new IllegalArgumentException("m3 must be greater than or equal to 0");
173
174      this.n1 = m0;
175      this.n2 = m1;
176      useTwoParameterConstructor = false;
177
178      // Create the tetrahedron's geometry.
179      // It has 4 vertices and 6 edges.
180      final Vertex v0 = new Vertex( 1,  1,  1),
181                   v1 = new Vertex(-1,  1, -1),
182                   v2 = new Vertex( 1, -1, -1),
183                   v3 = new Vertex(-1, -1,  1);
184
185      addVertex(v0, v1, v2, v3);
186
187      addPrimitive(new LineSegment(0, 1),  //top (bottom) edge
188                   new LineSegment(2, 3),  //bottom (top) edge
189                   new LineSegment(0, 2),
190                   new LineSegment(0, 3),
191                   new LineSegment(1, 2),
192                   new LineSegment(1, 3));
193
194      fan(m0, 0, v1, v2, v3); // fan out from v0
195      fan(m1, 1, v0, v2, v3); // fan out from v1
196      fan(m2, 2, v0, v1, v3); // fan out from v2
197      fan(m3, 3, v0, v1, v2); // fan out from v3
198   }
199
200
201   /**
202      Create {@code n} line segments fanning out from {@link Vertex}
203      {@code v0} towards the three edges spanned by the other three
204      vertices.
205
206      @param n   number of lines fanning out from {@link Vertex} {@code v0}
207      @param v0  index in the {@link Vertex} list of the vertex to fan out from
208      @param v1  a {@link Vertex} opposite to {@code v0}
209      @param v2  a {@link Vertex} opposite to {@code v0}
210      @param v3  a {@link Vertex} opposite to {@code v0}
211   */
212   private void fan(final int n, final int v0, final Vertex v1,
213                                               final Vertex v2,
214                                               final Vertex v3)
215   {
216      fan(n, v0, v1, v2);
217      fan(n, v0, v2, v3);
218      fan(n, v0, v3, v1);
219   }
220
221
222   /**
223      Create {@code n} line segments fanning out from {@link Vertex}
224      {@code v0} towards the edge spanned by the other two vertices.
225
226      @param n   number of lines fanning out from {@link Vertex} {@code v0}
227      @param v0  index in the {@link Vertex} list of the vertex to fan out from
228      @param v1  a {@link Vertex} opposite to {@code v0}
229      @param v2  a {@link Vertex} opposite to {@code v0}
230   */
231   private void fan(final int n, final int v0, final Vertex v1,
232                                               final Vertex v2)
233   {
234      for (int i = 0; i < n; ++i)
235      {
236         // Use linear interpolation (lerp).
237         final double t = (double)(i+1) / (double)(n+1);
238         final double x = (1-t) * v1.x + t * v2.x;
239         final double y = (1-t) * v1.y + t * v2.y;
240         final double z = (1-t) * v1.z + t * v2.z;
241         final Vertex v = new Vertex(x, y, z);
242         final int index = vertexList.size();
243         addVertex(v);
244         addPrimitive(new LineSegment(v0, index));
245      }
246   }
247
248
249
250   // Implement the MeshMaker interface (three methods).
251   @Override public int getHorzCount() {return this.n1;}
252
253   @Override public int getVertCount() {return this.n2;}
254
255   @Override
256   public Tetrahedron remake(final int n, final int k)
257   {
258      if (useTwoParameterConstructor)
259         return new Tetrahedron(n, k);
260      else
261         return new Tetrahedron(n, k, k, n);
262   }
263}//Tetrahedron