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 octahedron
015   with its center at the origin, having side length
016   {@code  sqrt(2) = 1.4142},with its center plane given
017   by the four vertices {@code  (±1, 0, ±1)}. and with
018   the top and bottom vertices being {@code  (0, ±1, 0)}.
019<p>
020   See <a href="https://en.wikipedia.org/wiki/Octahedron" target="_top">
021                https://en.wikipedia.org/wiki/Octahedron</a>
022
023   @see Tetrahedron
024   @see Cube
025   @see Icosahedron
026   @see Dodecahedron
027*/
028public class Octahedron extends Model implements MeshMaker
029{
030   public final int n1;
031   public final int n2;
032   public final int n3;
033
034   /**
035      Create a regular octahedron with its center at the
036      origin, having side length {@code  sqrt(2) = 1.4142},
037      with its center plane given by the four vertices
038      {@code  (±1, 0, ±1)}. and with the top and bottom
039      vertices being {@code  (0, ±1, 0)}.
040   */
041   public Octahedron()
042   {
043      super("Octahedron");
044
045      this.n1 = 0;
046      this.n2 = 0;
047      this.n3 = 0;
048
049      // Create the octahedron's geometry.
050      // It has 6 vertices and 12 edges.
051      addVertex(new Vertex( 1,  0,  0),  // 4 vertices around the center plane
052                new Vertex( 0,  0, -1),
053                new Vertex(-1,  0,  0),
054                new Vertex( 0,  0,  1),
055                new Vertex( 0,  1,  0),  // vertex at the top
056                new Vertex( 0, -1,  0)); // vertex at the bottom
057/*
058      // These vertices create an Octahedron with side length 1.
059      final double sqrt3 = Math.sqrt(3.0);
060      final double sqrt2 = Math.sqrt(2.0);
061      addVertex(new Vertex( 0.5, 0,  0.5), // 4 vertices around the center plane
062                new Vertex(-0.5, 0,  0.5),
063                new Vertex(-0.5, 0, -0.5),
064                new Vertex( 0.5, 0, -0.5),
065                new Vertex( 0,  1/sqrt2, 0),  // vertex at the top
066                new Vertex( 0, -1/sqrt2, 0)); // vertex at the bottom
067*/
068      // Create 12 line segments.
069      // Four line segments around the center plane.
070      addPrimitive(new LineSegment(0, 1),
071                   new LineSegment(1, 2),
072                   new LineSegment(2, 3),
073                   new LineSegment(3, 0));
074      // Edges going to the top vertex.
075      addPrimitive(new LineSegment(0, 4),
076                   new LineSegment(1, 4),
077                   new LineSegment(2, 4),
078                   new LineSegment(3, 4));
079      // Edges going to the bottom vertex.
080      addPrimitive(new LineSegment(0, 5),
081                   new LineSegment(1, 5),
082                   new LineSegment(2, 5),
083                   new LineSegment(3, 5));
084   }
085
086
087   /**
088      Create a regular octahedron with its center at the
089      origin, having side length {@code  sqrt(2) = 1.4142},
090      with its center plane given by the four vertices
091      {@code  (±1, 0, ±1)}. and with the top and bottom
092      vertices being {@code  (0, ±1, 0)}.
093      <p>
094      Add line segments fanning out from the top and bottom
095      vertices to the sides around the center plane.
096
097      @param n number of lines fanning out from the top and bottom on each side of the octahedron
098      @throws IllegalArgumentException if {@code n1} is less than 0
099      @throws IllegalArgumentException if {@code n2} is less than 0
100   */
101   public Octahedron(final int n)
102   {
103      this(n, 0, 0);
104   }
105
106
107   /**
108      Create a regular octahedron with its center at the
109      origin, having side length {@code  sqrt(2) = 1.4142},
110      with its center plane given by the four vertices
111      {@code  (±1, 0, ±1)}. and with the top and bottom
112      vertices being {@code  (0, ±1, 0)}.
113      <p>
114      Add line segments fanning out from each vertex to
115      its opposite sides.
116
117      @param n1 number of lines fanning out from the top and bottom on each side of the octahedron
118      @param n2 number of lines fanning out from v0 and v2 on each side of the octahedron
119      @param n3 number of lines fanning out from v1 and v3 on each side of the octahedron
120      @throws IllegalArgumentException if {@code n1} is less than 0
121      @throws IllegalArgumentException if {@code n2} is less than 0
122      @throws IllegalArgumentException if {@code n3} is less than 0
123   */
124   public Octahedron(final int n1, final int n2, final int n3)
125   {
126      this(n1, n1, n2, n2, n3, n3);
127   }
128
129
130   /**
131      Create a regular octahedron with its center at the
132      origin, having side length {@code  sqrt(2) = 1.4142},
133      with its center plane given by the four vertices
134      {@code  (±1, 0, ±1)}. and with the top and bottom
135      vertices being {@code  (0, ±1, 0)}.
136      <p>
137      Add line segments fanning out from each vertex to
138      its opposite sides.
139
140      @param n1a number of lines fanning out from the top on each side of the octahedron
141      @param n1b number of lines fanning out from the bottom on each side of the octahedron
142      @param n2a number of lines fanning out from v0 on each side of the octahedron
143      @param n2b number of lines fanning out from v1 on each side of the octahedron
144      @param n3a number of lines fanning out from v2 on each side of the octahedron
145      @param n3b number of lines fanning out from v3 on each side of the octahedron
146      @throws IllegalArgumentException if {@code n1a} is less than 0
147      @throws IllegalArgumentException if {@code n1b} is less than 0
148      @throws IllegalArgumentException if {@code n2a} is less than 0
149      @throws IllegalArgumentException if {@code n2b} is less than 0
150      @throws IllegalArgumentException if {@code n3a} is less than 0
151      @throws IllegalArgumentException if {@code n3b} is less than 0
152   */
153   public Octahedron(final int n1a, final int n1b,
154                     final int n2a, final int n2b,
155                     final int n3a, final int n3b)
156   {
157      super(String.format("Octahedron(%d,%d,%d,%d,%d,%d)",n1a,n1b,n2a,n2b,n3a,n3b));
158
159      if (n1a < 0)
160         throw new IllegalArgumentException("n1 must be greater than or equal to 0");
161      if (n1b < 0)
162         throw new IllegalArgumentException("n1 must be greater than or equal to 0");
163      if (n2a < 0)
164         throw new IllegalArgumentException("n2 must be greater than or equal to 0");
165      if (n2b < 0)
166         throw new IllegalArgumentException("n2 must be greater than or equal to 0");
167      if (n3a < 0)
168         throw new IllegalArgumentException("n3 must be greater than or equal to 0");
169      if (n3b < 0)
170         throw new IllegalArgumentException("n3 must be greater than or equal to 0");
171
172      this.n1 = n1a;
173      this.n2 = n2a;
174      this.n3 = n3a;
175
176      // Create the octahedron's geometry.
177      // It has 6 vertices and 12 edges.
178      final Vertex v0 = new Vertex( 1,  0,  0); // 4 vertices around the center plane
179      final Vertex v1 = new Vertex( 0,  0, -1);
180      final Vertex v2 = new Vertex(-1,  0,  0);
181      final Vertex v3 = new Vertex( 0,  0,  1);
182      final Vertex v4 = new Vertex( 0,  1,  0); // vertex at the top
183      final Vertex v5 = new Vertex( 0, -1,  0); // vertex at the bottom
184      addVertex(v0, v1, v2, v3, v4, v5);
185/*
186      // These vertices create an Octahedron with side length 1.
187      final double sqrt3 = Math.sqrt(3.0);
188      final double sqrt2 = Math.sqrt(2.0);
189      final Vertex v0 = new Vertex( 0.5, 0,  0.5); // 4 vertices around the center plane
190      final Vertex v1 = new Vertex(-0.5, 0,  0.5);
191      final Vertex v2 = new Vertex(-0.5, 0, -0.5);
192      final Vertex v3 = new Vertex( 0.5, 0, -0.5);
193      final Vertex v4 = new Vertex( 0,  1/sqrt2, 0); // vertex at the top
194      final Vertex v5 = new Vertex( 0, -1/sqrt2, 0); // vertex at the bottom
195      addVertex(v0, v1, v2, v3, v4, v5);
196*/
197      // Create 12 line segments.
198      // four line segments around the center plane
199      addPrimitive(new LineSegment(0, 1),
200                   new LineSegment(1, 2),
201                   new LineSegment(2, 3),
202                   new LineSegment(3, 0));
203      // edges going to the top vertex
204      addPrimitive(new LineSegment(0, 4),
205                   new LineSegment(1, 4),
206                   new LineSegment(2, 4),
207                   new LineSegment(3, 4));
208      // edges going to the bottom vertex
209      addPrimitive(new LineSegment(0, 5),
210                   new LineSegment(1, 5),
211                   new LineSegment(2, 5),
212                   new LineSegment(3, 5));
213
214      fan(n1a, 4, v0, v1, v2, v3); // fan out from v4 (top)
215      fan(n1b, 5, v0, v1, v2, v3); // fan out from v5 (bottom)
216      fan(n2a, 0, v3, v4, v1, v5); // fan out from v0
217      fan(n3a, 1, v0, v4, v2, v5); // fan out from v1
218      fan(n2b, 2, v1, v4, v3, v5); // fan out from v2
219      fan(n3b, 3, v2, v4, v0, v5); // fan out from v3
220   }
221
222
223   /**
224      Create {@code n} line segments fanning out from {@link Vertex}
225      {@code v0} towards the four edges spanned by the other four
226      vertices.
227
228      @param n   number of lines fanning out from {@link Vertex} {@code v0}
229      @param v0  index in the {@link Vertex} list of the vertex to fan out from
230      @param v1  a {@link Vertex} opposite to {@code v0}
231      @param v2  a {@link Vertex} opposite to {@code v0}
232      @param v3  a {@link Vertex} opposite to {@code v0}
233      @param v4  a {@link Vertex} opposite to {@code v0}
234   */
235   private void fan(final int n, final int v0, final Vertex v1,
236                                               final Vertex v2,
237                                               final Vertex v3,
238                                               final Vertex v4)
239   {
240      for (int i = 0; i < n; ++i)
241      {
242         // Use linear interpolation (lerp).
243         final double t = (double)(i+1) / (double)(n+1);
244         final double x = (1-t) * v1.x + t * v2.x;
245         final double y = (1-t) * v1.y + t * v2.y;
246         final double z = (1-t) * v1.z + t * v2.z;
247         final Vertex v = new Vertex(x, y, z);
248         final int index = vertexList.size();
249         addVertex(v);
250         addPrimitive(new LineSegment(v0, index));
251      }
252      for (int i = 0; i < n; ++i)
253      {
254         // Use linear interpolation (lerp).
255         final double t = (double)(i+1) / (double)(n+1);
256         final double x = (1-t) * v2.x + t * v3.x;
257         final double y = (1-t) * v2.y + t * v3.y;
258         final double z = (1-t) * v2.z + t * v3.z;
259         final Vertex v = new Vertex(x, y, z);
260         final int index = vertexList.size();
261         addVertex(v);
262         addPrimitive(new LineSegment(v0, index));
263      }
264      for (int i = 0; i < n; ++i)
265      {
266         // Use linear interpolation (lerp).
267         final double t = (double)(i+1) / (double)(n+1);
268         final double x = (1-t) * v3.x + t * v4.x;
269         final double y = (1-t) * v3.y + t * v4.y;
270         final double z = (1-t) * v3.z + t * v4.z;
271         final Vertex v = new Vertex(x, y, z);
272         final int index = vertexList.size();
273         addVertex(v);
274         addPrimitive(new LineSegment(v0, index));
275      }
276      for (int i = 0; i < n; ++i)
277      {
278         // Use linear interpolation (lerp).
279         final double t = (double)(i+1) / (double)(n+1);
280         final double x = (1-t) * v4.x + t * v1.x;
281         final double y = (1-t) * v4.y + t * v1.y;
282         final double z = (1-t) * v4.z + t * v1.z;
283         final Vertex v = new Vertex(x, y, z);
284         final int index = vertexList.size();
285         addVertex(v);
286         addPrimitive(new LineSegment(v0, index));
287      }
288   }
289
290
291
292   // Implement the MeshMaker interface (three methods).
293   @Override public int getHorzCount() {return this.n1;}
294
295   @Override public int getVertCount() {return this.n2;}
296
297   @Override
298   public Octahedron remake(final int n, final int k)
299   {
300      return new Octahedron(n, k, this.n3);
301   }
302}//Octahedron