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