1 /* BurrTools
2 *
3 * BurrTools is the legal property of its developers, whose
4 * names are listed in the COPYRIGHT file, which is included
5 * within the source distribution.
6 *
7 * This program is free software; you can redistribute it and/or
8 * modify it under the terms of the GNU General Public License
9 * as published by the Free Software Foundation; either version 2
10 * of the License, or (at your option) any later version.
11
12 * This program is distributed in the hope that it will be useful,
13 * but WITHOUT ANY WARRANTY; without even the implied warranty of
14 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15 * GNU General Public License for more details.
16
17 * You should have received a copy of the GNU General Public License
18 * along with this program; if not, write to the Free Software
19 * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
20 */
21 #include "voxel_2.h"
22
23 #include "puzzle.h"
24
25 #include "../halfedge/polyhedron.h"
26
27 #include "math.h"
28
29 /* this file contains the mesh generation part of voxel_2. This is so big for the spheres
30 * that I didn't want to put it into the normal file
31 */
32
33 #define Epsilon 1.0e-6
34
35 /* makes a sphere */
36
37 /* These are the points where the spheres touch (called touch point),
38 * corresponding to the faces of a rhombic dodecahedron.
39 * The order must be the same as in neighbor calculation.
40 */
41 static int connectionPoints[12][3] = {
42 {-1,-1, 0}, {-1,+1, 0}, {+1,-1, 0}, {+1,+1, 0},
43 {-1, 0,-1}, {-1, 0,+1}, {+1, 0,-1}, {+1, 0,+1},
44 { 0,-1,-1}, { 0,-1,+1}, { 0,+1,-1}, { 0,+1,+1}
45 };
46
47 /* Six points surrounding each touch point that
48 * correspond (roughly) to the connecting cylinder.
49 * they are all on a circle around the touch point but not equally space, only roughly equally
50 *
51 * As the touch point surrounding circles do have their maximal radius the circles touch, that
52 * is where those point given below are.
53 *
54 * We do not really give the real point but only a vector that is a direction seen from the center
55 * of the sphere, when you scale that vector to the radius of the sphere you will end up at the points
56 *
57 * As those points are exactly at the middle between 2 touching points all we need to do is take the average
58 * of the corresponding 2 touching points, the comment behind a line shows which 2 touching points are taken
59 *
60 * For the remaining 2 of the 6 points the other point we take the main axis to do the averaging with, this
61 * is not really on the circle but only in the direction where we want the point to be. It works anyway because
62 * before using a point we shift coordinates until they are on the circle
63 *
64 * if you cut the sphere in half so that a touching point is on the cutting plane and then connect center of
65 * the sphere with the 2 points on the circle of the cut sphere where the touching circle lies you will get
66 * an equilateral triangle, to the angle of the circle is 60 degree
67 */
68 static int holeTouchPoints[12][6][3] = {
69 {
70 {-1+0, -1-1, 0},
71 {-1+0, -1-1, 0+1}, // 0+9
72 {-1-1, -1+0, 0+1}, // 0+5
73 {-1-1, -1+0, 0},
74 {-1-1, -1+0, 0-1}, // 0+4
75 {-1+0, -1-1, 0-1}, // 0+8
76 },{
77 {-1+0, +1+1, 0},
78 {-1+0, +1+1, 0-1}, // 1+10
79 {-1-1, +1+0, 0-1}, // 1+4
80 {-1-1, +1+0, 0},
81 {-1-1, +1+0, 0+1}, // 1+5
82 {-1+0, +1+1, 0+1}, // 1+11
83 },{
84 {+1+1, -1+0, 0+1}, // 2+7
85 {+1+0, -1-1, 0+1}, // 2+9
86 {+1+0, -1-1, 0},
87 {+1+0, -1-1, 0-1}, // 2+8
88 {+1+1, -1+0, 0-1}, // 2+6
89 {+1+1, -1+0, 0}
90 },{
91 {+1+1, +1+0, 0-1}, // 3+6
92 {+1+0, +1+1, 0-1}, // 3+10
93 {+1+0, +1+1, 0},
94 {+1+0, +1+1, 0+1}, // 3+11
95 {+1+1, +1+0, 0+1}, // 3+7
96 {+1+1, +1+0, 0}
97 },{
98 {-1+0, 0-1, -1-1}, // 4+8
99 {-1-1, 0-1, -1+0}, // 4+0
100 {-1-1, 0, -1+0},
101 {-1-1, 0+1, -1+0}, // 4+1
102 {-1+0, 0+1, -1-1}, // 4+10
103 {-1+0, 0, -1-1}
104 },{
105 {-1-1, 0-1, +1+0}, // 5+0
106 {-1+0, 0-1, +1+1}, // 5+9
107 {-1+0, 0, +1+1},
108 {-1+0, 0+1, +1+1}, // 5+11
109 {-1-1, 0+1, +1+0}, // 5+1
110 {-1-1, 0, +1+0}
111 },{
112 {+1+1, 0-1, -1+0}, // 6+2
113 {+1+0, 0-1, -1-1}, // 6+8
114 {+1+0, 0, -1-1},
115 {+1+0, 0+1, -1-1}, // 6+10
116 {+1+1, 0+1, -1+0}, // 6+3
117 {+1+1, 0, -1+0}
118 },{
119 {+1+1, 0, +1+0},
120 {+1+1, 0+1, +1+0}, // 7+3
121 {+1+0, 0+1, +1+1}, // 7+11
122 {+1+0, 0, +1+1},
123 {+1+0, 0-1, +1+1}, // 7+9
124 {+1+1, 0-1, +1+0} // 7+2
125 },{
126 {0, -1+0, -1-1},
127 {0+1, -1+0, -1-1}, // 8+6
128 {0+1, -1-1, -1+0}, // 8+2
129 {0, -1-1, -1+0},
130 {0-1, -1-1, -1+0}, // 8+0
131 {0-1, -1+0, -1-1}, // 8+4
132 },{
133 {0+1, -1-1, +1+0}, // 9+2
134 {0+1, -1+0, +1+1}, // 9+7
135 {0, -1+0, +1+1},
136 {0-1, -1+0, +1+1}, // 9+5
137 {0-1, -1-1, +1+0}, // 9+0
138 {0, -1-1, +1+0}
139 },{
140 {0, +1+0, -1-1},
141 {0-1, +1+0, -1-1}, // 10+4
142 {0-1, +1+1, -1+0}, // 10+1
143 {0, +1+1, -1+0},
144 {0+1, +1+1, -1+0}, // 10+3
145 {0+1, +1+0, -1-1} // 10+6
146 },{
147 {0-1, +1+1, +1+0}, // 11+1
148 {0-1, +1+0, +1+1}, // 11+5
149 {0, +1+0, +1+1},
150 {0+1, +1+0, +1+1}, // 11+7
151 {0+1, +1+1, +1+0}, // 11+3
152 {0, +1+1, +1+0},
153 }
154 };
155
156 /* These correspond to 3 triangles around the eight obtuse
157 * vertices of a rhombic dodecahedron (3 faces meet).
158 *
159 * we have the point defined as above for the circles and one additional value
160 * that defines, what is the touching point that lies on the edge towards the next point in the list
161 * (or the first point for the last entry)
162 *
163 * important to note is that the point must be in counter clockwise order, because we need
164 * to generate all triangles in counter clockwise order so that we know where the normal points to
165 */
166 static int trianglePoints[8][3][3+1] = {
167 {
168 {+1+0, 0+1, +1+1, 7}, // 7+11
169 {+1+1, +1+0, 0+1, 3}, // 3+7
170 {0+1, +1+1, +1+0, 11} // 11+3
171 },{
172 {+1+1, +1+0, 0-1, 6}, // 3+6
173 {+1+0, 0+1, -1-1, 10}, // 6+10
174 {0+1, +1+1, -1+0, 3} // 10+3
175 },{
176 {+1+1, 0-1, -1+0, 2}, // 6+2
177 {+1+0, -1-1, 0-1, 8}, // 2+8
178 {0+1, -1+0, -1-1, 6} // 8+6
179 },{
180 {0-1, +1+0, -1-1, 4}, // 10+4
181 {-1-1, 0+1, -1+0, 1}, // 4+1
182 {-1+0, +1+1, 0-1, 10} // 1+10
183 },{
184 {-1+0, 0-1, -1-1, 8}, // 4+8
185 {0-1, -1-1, -1+0, 0}, // 8+0
186 {-1-1, -1+0, 0-1, 4} // 0+4
187 },{
188 {0-1, +1+0, +1+1, 11}, // 11+5
189 {-1+0, +1+1, 0+1, 1}, // 1+11
190 {-1-1, 0+1, +1+0, 5} // 5+1
191 },{
192 {-1+0, -1-1, 0+1, 9}, // 0+9
193 {0-1, -1+0, +1+1, 5}, // 9+5
194 {-1-1, 0-1, +1+0, 0} // 5+0
195 },{
196 {+1+1, -1+0, 0+1, 7}, // 2+7
197 {+1+0, 0-1, +1+1, 9}, // 7+9
198 {0+1, -1-1, +1+0, 2} // 9+2
199 }
200 };
201
202 /* These correspond to 6 triangles around the six acute
203 * vertices of a rhombic dodecahedron (4 faces meet).
204 * Two of these triangles form a square, the other four
205 * share an edge with each side of the square.
206 * The shape of all 6 triangles form a star-shape.
207 *
208 * otherwise the same notes apply as for the trianglePoints array above
209 */
210 static int squarePoints[6][8][4] = {
211 {
212 {0, +1+0, -1-1, 10},
213 {0+1, +1+0, -1-1}, // 10+6
214 {+1+0, 0, -1-1, 6},
215 {+1+0, 0-1, -1-1}, // 6+8
216 {0, -1+0, -1-1, 8},
217 {0-1, -1+0, -1-1}, // 8+4
218 {-1+0, 0, -1-1, 4},
219 {-1+0, 0+1, -1-1}, // 4+10
220 },{
221 {-1-1, 0, -1+0, 4},
222 {-1-1, 0-1, -1+0}, // 4+0
223 {-1-1, -1+0, 0, 0},
224 {-1-1, -1+0, 0+1}, // 0+5
225 {-1-1, 0, +1+0, 5},
226 {-1-1, 0+1, +1+0}, // 5+1
227 {-1-1, +1+0, 0, 1},
228 {-1-1, +1+0, 0-1}, // 1+4
229 },{
230 {+1+0, -1-1, 0, 2},
231 {+1+0, -1-1, 0+1}, // 2+9
232 {0, -1-1, +1+0, 9},
233 {0-1, -1-1, +1+0}, // 9+0
234 {-1+0, -1-1, 0, 0},
235 {-1+0, -1-1, 0-1}, // 0+8
236 {0, -1-1, -1+0, 8},
237 {0+1, -1-1, -1+0}, // 8+2
238 },{
239 {+1+1, +1+0, 0, 3},
240 {+1+1, 0+1, +1+0}, // 7+3
241 {+1+1, 0, +1+0, 7},
242 {+1+1, -1+0, 0+1}, // 2+7
243 {+1+1, -1+0, 0, 2},
244 {+1+1, 0-1, -1+0}, // 6+2
245 {+1+1, 0, -1+0, 6},
246 {+1+1, +1+0, 0-1}, // 3+6
247 },{
248 {0, +1+0, +1+1, 11},
249 {0-1, +1+0, +1+1}, // 11+5
250 {-1+0, 0, +1+1, 5},
251 {-1+0, 0-1, +1+1}, // 5+9
252 {0, -1+0, +1+1, 9},
253 {0+1, -1+0, +1+1}, // 9+7
254 {+1+0, 0, +1+1, 7},
255 {+1+0, 0+1, +1+1}, // 7+11
256 },{
257 {0, +1+1, +1+0, 11},
258 {+1+0, +1+1, 0+1}, // 3+11
259 {+1+0, +1+1, 0, 3},
260 {0+1, +1+1, -1+0}, // 10+3
261 {0, +1+1, -1+0, 10},
262 {-1+0, +1+1, 0-1}, // 1+10
263 {-1+0, +1+1, 0, 1},
264 {0-1, +1+1, +1+0}, // 11+1
265 }
266 };
267
268 // this structure contains all parameters that are used for
269 // the mesh generation, there are so many of them that it became
270 // unhandy to deliver them all as parameters to the different
271 // functions, instead we will just hand around a (const where possible) reference
272 typedef struct
273 {
274 float sphere_rad; // Radius of the sphere (outer layer)
275 float inner_rad; // Radius of the sphere (inner layer, radius of the hole)
276 float offset; // offset by which the sphere radii are made smaller (subtraction)
277 bool outside; // is currently drawn sphere the outer or inner sphere
278 float hole_diam; // diameter of the hole between inside and outside > 0 round hole, <0 square hole
279 float connection_rad;// radius of the connection between spheres (1 = maximal possible radius)
280 float xc, yc, zc; // center of the current sphere
281
282 // some internal values used to calculate the curve that makes up the transition between
283 // the sphere surface and the connection cylinder
284 float curvX;
285 float curvY;
286 float curvRad;
287 float holeStart;
288 float lineEnd;
289 float curvEnd;
290
291 // the vertex list, we add the triangles to
292 vertexList_c * vl;
293
294 // the flags to use for the triangles
295 int flags;
296 int fb_index;
297 int fb_face;
298 int color;
299
300 } genPar;
301
302
303 // add the triangle to the vertexList (and thus to the polyhedron)
304 //
outTriangle(float x1,float y1,float z1,float x2,float y2,float z2,float x3,float y3,float z3,genPar & par)305 static void outTriangle(
306 /* the 3 vertexes of the triangle */
307 float x1, float y1, float z1,
308 float x2, float y2, float z2,
309 float x3, float y3, float z3,
310 genPar & par)
311 {
312
313 // when outputting the vertices, we round the values to
314 // a multiple of 1/256. This will help us properly align vertices up to a very high degree
315 // and the power of 2 factor will make exact division possible for the floats
316 const float roundfac = 256;
317
318 x1 = roundf((par.xc+x1)*roundfac)/roundfac;
319 y1 = roundf((par.yc+y1)*roundfac)/roundfac;
320 z1 = roundf((par.zc+z1)*roundfac)/roundfac;
321
322 x2 = roundf((par.xc+x2)*roundfac)/roundfac;
323 y2 = roundf((par.yc+y2)*roundfac)/roundfac;
324 z2 = roundf((par.zc+z2)*roundfac)/roundfac;
325
326 x3 = roundf((par.xc+x3)*roundfac)/roundfac;
327 y3 = roundf((par.yc+y3)*roundfac)/roundfac;
328 z3 = roundf((par.zc+z3)*roundfac)/roundfac;
329
330 std::vector<int> face3(3);
331 face3[0] = par.vl->get(x1, y1, z1);
332 face3[1] = par.vl->get(x2, y2, z2);
333 face3[2] = par.vl->get(x3, y3, z3);
334
335 // don't add degenerate triangles
336 if (face3[0] == face3[1] || face3[0] == face3[2] || face3[1] == face3[2])
337 return;
338
339 Face * f = par.vl->addFace(face3);
340
341 f->_flags = par.flags;
342 f->_fb_index = par.fb_index;
343 f->_fb_face = par.fb_face;
344 f->_color = par.color;
345 }
346
347 // normalize a vector
normalize(float * x,float * y,float * z)348 static void normalize(float *x, float *y, float *z)
349 {
350 float l = sqrt(*x * *x + *y * *y + *z * *z);
351 *x /= l;
352 *y /= l;
353 *z /= l;
354 }
355
356 /* The given point is shifted away from the given touching
357 * point until it is on the 60 degree circle around that
358 * touching point.
359 * This gives the maximum size cylinder that can be used to
360 * connect the spheres. Such cylinders touch at the sphere
361 * surface, and have a diameter equal to the radius of the sphere.
362 */
shiftToHoleBorder(int nr,float * x,float * y,float * z)363 static void shiftToHoleBorder(int nr, float *x, float *y, float *z)
364 {
365 float l = sqrt(*x * *x + *y * *y + *z * *z);
366
367 /* ok some names
368 * M is the middle of the sphere (which is at the origin btw.)
369 * T is out touching point
370 * P is the input point
371 */
372
373 // calculate the angle at PMT
374 float a = acos((
375 connectionPoints[nr][0] * *x +
376 connectionPoints[nr][1] * *y +
377 connectionPoints[nr][2] * *z) / (l * sqrt(2)));
378
379 // what the heck, I don't understand any more what I did in here... bahh next time
380 // I will need to comment it as soon as it works
381 float b = 105*M_PI/180 - a;
382
383 float xl = sin(75*M_PI/180) / sin(b);
384
385 *x *= xl/l;
386 *y *= xl/l;
387 *z *= xl/l;
388
389 *x -= connectionPoints[nr][0]/sqrt(2);
390 *y -= connectionPoints[nr][1]/sqrt(2);
391 *z -= connectionPoints[nr][2]/sqrt(2);
392
393 normalize(x, y, z);
394
395 *x *= sin(30*M_PI/180)/sin(75*M_PI/180);
396 *y *= sin(30*M_PI/180)/sin(75*M_PI/180);
397 *z *= sin(30*M_PI/180)/sin(75*M_PI/180);
398
399 *x += connectionPoints[nr][0]/sqrt(2);
400 *y += connectionPoints[nr][1]/sqrt(2);
401 *z += connectionPoints[nr][2]/sqrt(2);
402 }
403
404 // recursively draw a spherical triangle on the perimeter of of
405 // a sphere, additionally it is possible to shift the edges of the
406 // triangle to that they are on the circle around the touching
407 // points of the sphere
drawTriangle(float x1,float y1,float z1,float x2,float y2,float z2,float x3,float y3,float z3,int edge12,int edge23,int edge31,int rec,genPar & par)408 static void drawTriangle(
409 // direction vectors for the 3 corners, the length is not important
410 // as the points will eventually be on the sphere
411 float x1, float y1, float z1,
412 float x2, float y2, float z2,
413 float x3, float y3, float z3,
414 // which touching circle to use for which edge, if negative no connection circle is used
415 // the recursion level tells how many times the triangle is subdivided multiplying
416 // the number of triangles by 4 each time
417 int edge12, int edge23, int edge31, int rec,
418 genPar & par)
419 {
420 // make the vectors unit length
421 normalize(&x1, &y1, &z1);
422 normalize(&x2, &y2, &z2);
423 normalize(&x3, &y3, &z3);
424
425 if (rec > 0)
426 {
427 // find the middle of the 3 triangle sides
428 float x12 = (x1+x2)/2;
429 float y12 = (y1+y2)/2;
430 float z12 = (z1+z2)/2;
431
432 float x23 = (x2+x3)/2;
433 float y23 = (y2+y3)/2;
434 float z23 = (z2+z3)/2;
435
436 float x31 = (x3+x1)/2;
437 float y31 = (y3+y1)/2;
438 float z31 = (z3+z1)/2;
439
440 // shift to the connection circles
441 if (edge12 >= 0) shiftToHoleBorder(edge12, &x12, &y12, &z12);
442 if (edge23 >= 0) shiftToHoleBorder(edge23, &x23, &y23, &z23);
443 if (edge31 >= 0) shiftToHoleBorder(edge31, &x31, &y31, &z31);
444
445 // recursively output the triangles, we need to keep the edge flags only for
446 // the sides of the triangles that are still on the outside
447 drawTriangle(x1, y1, z1, x12, y12, z12, x31, y31, z31, edge12, -1, edge31, rec-1, par);
448 drawTriangle(x2, y2, z2, x23, y23, z23, x12, y12, z12, edge23, -1, edge12, rec-1, par);
449 drawTriangle(x3, y3, z3, x31, y31, z31, x23, y23, z23, edge31, -1, edge23, rec-1, par);
450 drawTriangle(x12, y12, z12, x23, y23, z23, x31, y31, z31, -1, -1, -1, rec-1, par);
451 }
452 else
453 {
454
455 // final output, first find out the radius of
456 // the sphere we are on
457 float mult;
458
459 if (par.outside)
460 mult = par.sphere_rad-par.offset;
461 else
462 mult = par.inner_rad-par.offset;
463
464 // scale the triangle point onto the sphere
465 x1 *= mult;
466 y1 *= mult;
467 z1 *= mult;
468
469 x2 *= mult;
470 y2 *= mult;
471 z2 *= mult;
472
473 x3 *= mult;
474 y3 *= mult;
475 z3 *= mult;
476
477 // if not outside reverse the order of points to flip surface
478 if (par.outside)
479 outTriangle(x1, y1, z1, x2, y2, z2, x3, y3, z3, par);
480 else
481 outTriangle(x1, y1, z1, x3, y3, z3, x2, y2, z2, par);
482 }
483 }
484
485
486 /* when drawing a connection this function calculates
487 * the radius (meaning how far is the surfae away from the center of the sphere
488 * for a certain angle from the touching point
489 *
490 * this value is the sphere radius for the outer rim and will increase as the
491 * angle gets smaller and we get closer to the point, where the cylinsers touch
492 * inside of the cylinder the value is not defined
493 */
radius(float a,genPar & par)494 static float radius(float a, genPar & par)
495 {
496 /* this is a bit like raytracing of the situation transformed to 2d
497 * we are calculating 3 segments that construct the shape of the hole piece:
498 * - line where 2 spheres tough
499 * - circle of the curvature
500 * - arc of the circle of the sphere
501 * and then we intersect and find out on which piece we are
502 * and calculate the distance...
503 */
504
505 float m = tan(90*M_PI/180-a);
506
507 float linex = par.connection_rad*(par.sphere_rad-par.offset)/2;
508 float liney = m*linex;
509
510 float circlex = (par.sphere_rad-par.offset)*sin(a);
511 float circley = (par.sphere_rad-par.offset)*cos(a);
512
513 float curvex, curvey;
514
515 float ap = 1+m*m;
516 float bp = -2*par.curvX-2*m*par.curvY;
517 float cp = par.curvX*par.curvX+par.curvY*par.curvY-par.curvRad*par.curvRad;
518
519 if (fabs(ap) < Epsilon)
520 {
521 curvex = curvey = 1000000;
522 }
523 else
524 {
525 float p = bp/ap;
526 float q = cp/ap;
527
528 if (p*p/4-q >= 0)
529 {
530 curvex = -p/2-sqrt(p*p/4-q);
531 curvey = m*curvex;
532 }
533 else
534 {
535 curvex = curvey = 1000000;
536 }
537 }
538
539 float px = linex;
540 float py = liney;
541
542 if (liney < curvey && curvey < 10000)
543 {
544 px = curvex;
545 py = curvey;
546 }
547
548 if (m*par.curvX < par.curvY)
549 {
550 px = circlex;
551 py = circley;
552 }
553
554 return sqrt(px*px + py*py);
555 }
556
557
findPointOnArc(float xs,float ys,float zs,float xe,float ye,float ze,float arc,float * x,float * y,float * z)558 static void findPointOnArc(float xs, float ys, float zs, float xe, float ye, float ze, float arc,
559 float *x, float *y, float *z )
560 {
561 float ls = sqrt(xs*xs+ys*ys+zs*zs);
562 float le = sqrt(xe*xe+ye*ye+ze*ze);
563
564 float a = (xs*xe+ys*ye+zs*ze)/(ls*le);
565
566 if (arc >= a)
567 {
568 *x = xe;
569 *y = ye;
570 *z = ze;
571
572 return;
573 }
574
575 float ws = 0;
576 float we = 1;
577
578 while (fabs(ws-we) > Epsilon)
579 {
580 float w = (ws+we)/2;
581
582 *x = (1-w)*xs+w*xe;
583 *y = (1-w)*ys+w*ye;
584 *z = (1-w)*zs+w*ze;
585
586 float l = sqrt(*x * *x + *y * *y + *z * *z);
587 a = acos((*x * xs + *y * ys + *z * zs)/(l*ls));
588
589 if (arc < a)
590 {
591 we = w;
592 }
593 else
594 {
595 ws = w;
596 }
597 }
598 }
599
drawHolePiece(int i,float start,float end,float x1,float y1,float z1,float x2,float y2,float z2,int rec,genPar & par)600 static void drawHolePiece(
601 int i,
602 float start, float end,
603 float x1, float y1, float z1,
604 float x2, float y2, float z2,
605 int rec,
606 genPar & par)
607 {
608 if (rec > 0 && fabs(start-end) > Epsilon)
609 {
610 drawHolePiece(i, start, (start+end)/2, x1, y1, z1, x2, y2, z2, rec-1, par);
611 drawHolePiece(i, (start+end)/2, end, x1, y1, z1, x2, y2, z2, rec-1, par);
612 }
613 else
614 {
615 float x1s, y1s, z1s, x2s, y2s, z2s, x1e, y1e, z1e, x2e, y2e, z2e;
616
617 findPointOnArc(connectionPoints[i][0], connectionPoints[i][1], connectionPoints[i][2], x1, y1, z1, start, &x1s, &y1s, &z1s);
618 findPointOnArc(connectionPoints[i][0], connectionPoints[i][1], connectionPoints[i][2], x2, y2, z2, start, &x2s, &y2s, &z2s);
619 findPointOnArc(connectionPoints[i][0], connectionPoints[i][1], connectionPoints[i][2], x1, y1, z1, end, &x1e, &y1e, &z1e);
620 findPointOnArc(connectionPoints[i][0], connectionPoints[i][1], connectionPoints[i][2], x2, y2, z2, end, &x2e, &y2e, &z2e);
621
622 float rs = radius(start, par);
623 float re = radius(end, par);
624
625 float l;
626 l = sqrt(x1s*x1s+y1s*y1s+z1s*z1s); x1s *= rs/l; y1s *= rs/l; z1s *= rs/l;
627 l = sqrt(x2s*x2s+y2s*y2s+z2s*z2s); x2s *= rs/l; y2s *= rs/l; z2s *= rs/l;
628
629 l = sqrt(x1e*x1e+y1e*y1e+z1e*z1e); x1e *= re/l; y1e *= re/l; z1e *= re/l;
630 l = sqrt(x2e*x2e+y2e*y2e+z2e*z2e); x2e *= re/l; y2e *= re/l; z2e *= re/l;
631
632 outTriangle(x2s, y2s, z2s, x1s, y1s, z1s, x2e, y2e, z2e, par);
633 outTriangle(x1s, y1s, z1s, x1e, y1e, z1e, x2e, y2e, z2e, par);
634 }
635 }
636
637 /* generate the connection between 2 spheres
638 * this connection starts on the sphere surface and slowly (via a rounding circle)
639 * warps into the connection cylinder
640 *
641 * the function really only draws a pie shaped piece of the connection that
642 * may be recursively split into smaller pie shaped pieces
643 */
drawHole(int i,float x1,float y1,float z1,float x2,float y2,float z2,int rec,int rec2,genPar & par)644 static void drawHole(
645 /* which touching point */
646 int i,
647 /* the 2 corners of the pie shaped piece where the hole is placed in between */
648 float x1, float y1, float z1, float x2, float y2, float z2,
649 /* number of recursion levels for this pie division, and number of recursion levels for
650 * when the pie piece is drawn
651 */
652 int rec, int rec2,
653 genPar & par)
654 {
655 if (rec > 0)
656 {
657 // find the middle between the 2 points
658 normalize(&x1, &y1, &z1);
659 normalize(&x2, &y2, &z2);
660
661 float px = (x1+x2)/2;
662 float py = (y1+y2)/2;
663 float pz = (z1+z2)/2;
664
665 // shift that point to the edge of the touching circle
666 shiftToHoleBorder(i, &px, &py, &pz);
667
668 // draw the 2 pies to the left and the right
669 drawHole(i, x1, y1, z1, px, py, pz, rec-1, rec2, par);
670 drawHole(i, px, py, pz, x2, y2, z2, rec-1, rec2, par);
671 }
672 else
673 {
674 // Outermost section of the connection (farthest from center)
675 if (par.holeStart < par.lineEnd)
676 drawHolePiece(i, par.holeStart, par.lineEnd, x1, y1, z1, x2, y2, z2, 0, par);
677
678 // Curvature transition
679 if (par.lineEnd < par.curvEnd)
680 drawHolePiece(i, par.lineEnd, par.curvEnd, x1, y1, z1, x2, y2, z2, rec2, par);
681
682 // Innermost, transition to the connector
683 if (par.curvEnd < 30*M_PI/180)
684 drawHolePiece(i, par.curvEnd, 30*M_PI/180, x1, y1, z1, x2, y2, z2, rec2, par);
685 }
686 }
687
688
689 /* Shift the given point along the line connecting (x, y, z) to (px, py, pz) until
690 * it is a distance rad from this point (px, py, pz).
691 */
shiftToConnectingHole(float px,float py,float pz,float rad,float * x,float * y,float * z)692 static void shiftToConnectingHole(float px, float py, float pz, float rad,
693 float *x, float *y, float *z)
694 {
695 float diff = sqrt((px-*x)*(px-*x)+(py-*y)*(py-*y)+(pz-*z)*(pz-*z));
696
697 if (diff < Epsilon) return;
698
699 float s = 1.0 - rad/diff;
700
701 *x = *x + s*(px-*x);
702 *y = *y + s*(py-*y);
703 *z = *z + s*(pz-*z);
704
705 normalize(x, y, z);
706 }
707
708 /* Draw the connecting faces between the inside and outside of the sphere.
709 * Simply draw two triangles between two pairs of inside and outside points.
710 */
drawConnectingTriangle(float x1,float y1,float z1,float x2,float y2,float z2,genPar & par)711 static void drawConnectingTriangle(
712 float x1, float y1, float z1,
713 float x2, float y2, float z2,
714 genPar & par)
715 {
716 normalize(&x1, &y1, &z1);
717 normalize(&x2, &y2, &z2);
718
719 // calculate the points that are on the outer sphere
720 float x3 = x2*(par.sphere_rad-par.offset);
721 float y3 = y2*(par.sphere_rad-par.offset);
722 float z3 = z2*(par.sphere_rad-par.offset);
723
724 float x4 = x1*(par.sphere_rad-par.offset);
725 float y4 = y1*(par.sphere_rad-par.offset);
726 float z4 = z1*(par.sphere_rad-par.offset);
727
728 // the points for the inner sphere
729 float mult = par.inner_rad-par.offset;
730
731 x1 *= mult;
732 y1 *= mult;
733 z1 *= mult;
734
735 x2 *= mult;
736 y2 *= mult;
737 z2 *= mult;
738
739 outTriangle(x1, y1, z1, x3, y3, z3, x2, y2, z2, par);
740 outTriangle(x1, y1, z1, x4, y4, z4, x3, y3, z3, par);
741 }
742
743 /* The pattern of squares by variable name (x1,y1,z1), (x5,y5,z5), etc.
744 1 5 2
745 6 7 8
746 3 9 4
747
748 edgeflag & 1 means this square includes the top edge
749 edgeflag & 2 means this square includes the bottom edge
750 */
drawConnectingHole(float hx,float hy,float hz,float x1,float y1,float z1,float x2,float y2,float z2,float x3,float y3,float z3,float x4,float y4,float z4,int edgeflag,int rec,genPar & par)751 static void drawConnectingHole(
752 float hx, float hy, float hz,
753 float x1, float y1, float z1, float x2, float y2, float z2,
754 float x3, float y3, float z3, float x4, float y4, float z4,
755 int edgeflag, int rec,
756 genPar & par)
757 {
758 normalize(&x1, &y1, &z1);
759 normalize(&x2, &y2, &z2);
760 normalize(&x3, &y3, &z3);
761 normalize(&x4, &y4, &z4);
762
763 if (rec > 0)
764 {
765 float x9 = (x3 + x4)/2;
766 float y9 = (y3 + y4)/2;
767 float z9 = (z3 + z4)/2;
768
769 // Do these next lines to make round (circular) holes
770 // otherwise they will be square.
771 if (edgeflag & 2 && par.hole_diam > 0)
772 {
773 float connectingHoleRadius = 0.5 * par.hole_diam / par.sphere_rad;
774 shiftToConnectingHole(hx, hy, hz, connectingHoleRadius, &x9, &y9, &z9);
775 }
776
777 float x5 = (x1 + x2)/2;
778 float y5 = (y1 + y2)/2;
779 float z5 = (z1 + z2)/2;
780
781 float x6 = (x1 + x3)/2;
782 float y6 = (y1 + y3)/2;
783 float z6 = (z1 + z3)/2;
784
785 float x8 = (x2 + x4)/2;
786 float y8 = (y2 + y4)/2;
787 float z8 = (z2 + z4)/2;
788
789 float x7 = (x5 + x9)/2;
790 float y7 = (y5 + y9)/2;
791 float z7 = (z5 + z9)/2;
792
793 drawConnectingHole(hx, hy, hz,
794 x1, y1, z1, x5, y5, z5, x6, y6, z6, x7, y7, z7, edgeflag & 1, rec-1, par);
795 drawConnectingHole(hx, hy, hz,
796 x5, y5, z5, x2, y2, z2, x7, y7, z7, x8, y8, z8, edgeflag & 1, rec-1, par);
797 drawConnectingHole(hx, hy, hz,
798 x6, y6, z6, x7, y7, z7, x3, y3, z3, x9, y9, z9, edgeflag & 2, rec-1, par);
799 drawConnectingHole(hx, hy, hz,
800 x7, y7, z7, x8, y8, z8, x9, y9, z9, x4, y4, z4, edgeflag & 2, rec-1, par);
801
802 }
803 else
804 {
805 float diag23 = sqrt((x2-x3)*(x2-x3)+(y2-y3)*(y2-y3)+(z2-z3)*(z2-z3));
806 float diag14 = sqrt((x1-x4)*(x1-x4)+(y1-y4)*(y1-y4)+(z1-z4)*(z1-z4));
807
808 if (diag23 < diag14)
809 {
810 drawTriangle(x1, y1, z1, x2, y2, z2, x3, y3, z3, 0, 0, 0, 0, par);
811 drawTriangle(x2, y2, z2, x4, y4, z4, x3, y3, z3, 0, 0, 0, 0, par);
812 }
813 else
814 {
815 drawTriangle(x1, y1, z1, x2, y2, z2, x4, y4, z4, 0, 0, 0, 0, par);
816 drawTriangle(x1, y1, z1, x4, y4, z4, x3, y3, z3, 0, 0, 0, 0, par);
817 }
818
819 if ((edgeflag & 2) && par.outside)
820 {
821 drawConnectingTriangle(x3, y3, z3, x4, y4, z4, par);
822 }
823 }
824 }
825
826 /* create one sphere.
827 * neighbors shows, where we need connections to the neibors (each bit set means that
828 * there must be a connection cylinder, no bit set close the sphere) the bits are in
829 * the same order as the neighbors or connection points
830 *
831 * bollow specifies, whether the sphere is supposed to be hollow
832 * variable, shows, whether the sphere is supposed to be a variable sphere (use the bevel face as variable marker)
833 */
makeSphere(uint16_t neighbors,int recursion,bool hollow,bool variable,genPar & par)834 static void makeSphere(uint16_t neighbors, int recursion, bool hollow, bool variable, genPar & par)
835 {
836 /* first make the holes, or hole caps */
837 for (int i = 0; i < 12; i++)
838 {
839 float p1x = connectionPoints[i][0];
840 float p1y = connectionPoints[i][1];
841 float p1z = connectionPoints[i][2];
842
843 normalize(&p1x, &p1y, &p1z);
844
845 /* close the hole using 6 triangles */
846
847 for (int t = 0; t < 6; t++)
848 {
849 float p2x = holeTouchPoints[i][(t+0)%6][0];
850 float p2y = holeTouchPoints[i][(t+0)%6][1];
851 float p2z = holeTouchPoints[i][(t+0)%6][2];
852
853 float p3x = holeTouchPoints[i][(t+1)%6][0];
854 float p3y = holeTouchPoints[i][(t+1)%6][1];
855 float p3z = holeTouchPoints[i][(t+1)%6][2];
856
857 shiftToHoleBorder(i, &p2x, &p2y, &p2z);
858 shiftToHoleBorder(i, &p3x, &p3y, &p3z);
859
860 if ((neighbors & (1<<i)) && par.outside && (par.connection_rad > Epsilon))
861 {
862 /* make a proper hole (connection to next sphere) */
863 par.flags = FF_COLOR_LIGHT;
864 drawHole(i, p2x, p2y, p2z, p3x, p3y, p3z, (int)recursion, (int)recursion, par);
865 }
866 else
867 {
868 /* simply close the sphere with a sphere surface section
869 * those faces are the sensitive faces for appending another sphere
870 * they are drawn a bit darker
871 */
872 par.fb_face = i;
873 par.flags = 0;
874 drawTriangle(p1x, p1y, p1z, p2x, p2y, p2z, p3x, p3y, p3z, -1, i, -1, (int)recursion, par);
875 }
876 } // end loop over t
877 } // end loop over i
878
879 // when the sphere is a variable sphere, we use the variable face marker for the filling faces, this will end up with
880 // black faces, otherwise we use the light marker to get lighter faces than the clickable faces
881 if (variable)
882 par.flags = FF_VARIABLE_FACE;
883 else
884 par.flags = FF_COLOR_LIGHT;
885
886 // followind faces are supposed to stay, when in wire frame mode
887 par.flags |= FF_WIREFRAME;
888
889 /* fill the 8 triangular gaps */
890 for (int i = 0; i < 8; i++)
891 {
892 float p1x = trianglePoints[i][0][0];
893 float p1y = trianglePoints[i][0][1];
894 float p1z = trianglePoints[i][0][2];
895
896 float p2x = trianglePoints[i][1][0];
897 float p2y = trianglePoints[i][1][1];
898 float p2z = trianglePoints[i][1][2];
899
900 float p3x = trianglePoints[i][2][0];
901 float p3y = trianglePoints[i][2][1];
902 float p3z = trianglePoints[i][2][2];
903
904 shiftToHoleBorder(trianglePoints[i][0][3], &p1x, &p1y, &p1z);
905 shiftToHoleBorder(trianglePoints[i][1][3], &p2x, &p2y, &p2z);
906 shiftToHoleBorder(trianglePoints[i][2][3], &p3x, &p3y, &p3z);
907
908 drawTriangle(p1x, p1y, p1z, p2x, p2y, p2z, p3x, p3y, p3z,
909 trianglePoints[i][0][3],
910 trianglePoints[i][1][3],
911 trianglePoints[i][2][3],
912 (int)recursion, par);
913 }
914
915 /* finally the 6 square gaps */
916 for (int i = 0; i < 6; i++)
917 {
918 /* first fill the corners */
919 for (int k = 0; k < 4; k++) {
920 float p1x = squarePoints[i][(2*k+0)%8][0];
921 float p1y = squarePoints[i][(2*k+0)%8][1];
922 float p1z = squarePoints[i][(2*k+0)%8][2];
923
924 float p2x = squarePoints[i][(2*k+1)%8][0];
925 float p2y = squarePoints[i][(2*k+1)%8][1];
926 float p2z = squarePoints[i][(2*k+1)%8][2];
927
928 float p3x = squarePoints[i][(2*k+2)%8][0];
929 float p3y = squarePoints[i][(2*k+2)%8][1];
930 float p3z = squarePoints[i][(2*k+2)%8][2];
931
932 shiftToHoleBorder(squarePoints[i][(2*k+0)%8][3], &p1x, &p1y, &p1z);
933 shiftToHoleBorder(squarePoints[i][(2*k+0)%8][3], &p2x, &p2y, &p2z);
934 shiftToHoleBorder(squarePoints[i][(2*k+2)%8][3], &p3x, &p3y, &p3z);
935
936 drawTriangle(p1x, p1y, p1z, p2x, p2y, p2z, p3x, p3y, p3z,
937 squarePoints[i][(2*k+0)%8][3],
938 squarePoints[i][(2*k+2)%8][3],
939 -1,
940 (int)recursion, par);
941 }
942
943 /* Then the center square */
944 if (!hollow || fabs(par.hole_diam) < Epsilon)
945 { // not hollow or no holes
946 for (int k = 0; k < 2; k++)
947 {
948 float p1x = squarePoints[i][(4*k+0)%8][0];
949 float p1y = squarePoints[i][(4*k+0)%8][1];
950 float p1z = squarePoints[i][(4*k+0)%8][2];
951
952 float p2x = squarePoints[i][(4*k+2)%8][0];
953 float p2y = squarePoints[i][(4*k+2)%8][1];
954 float p2z = squarePoints[i][(4*k+2)%8][2];
955
956 float p3x = squarePoints[i][(4*k+4)%8][0];
957 float p3y = squarePoints[i][(4*k+4)%8][1];
958 float p3z = squarePoints[i][(4*k+4)%8][2];
959
960 shiftToHoleBorder(squarePoints[i][(4*k+0)%8][3], &p1x, &p1y, &p1z);
961 shiftToHoleBorder(squarePoints[i][(4*k+2)%8][3], &p2x, &p2y, &p2z);
962 shiftToHoleBorder(squarePoints[i][(4*k+4)%8][3], &p3x, &p3y, &p3z);
963
964 drawTriangle(p1x, p1y, p1z, p2x, p2y, p2z, p3x, p3y, p3z,
965 -1, -1, -1, (int)recursion, par);
966 }
967 }
968 else
969 { //hollow with holes
970
971 // hx,hy,hz, location of the center of the hole into the interior
972 float hx = 0.125*(squarePoints[i][0][0] + squarePoints[i][2][0] +
973 squarePoints[i][4][0] + squarePoints[i][6][0]);
974 float hy = 0.125*(squarePoints[i][0][1] + squarePoints[i][2][1] +
975 squarePoints[i][4][1] + squarePoints[i][6][1]);
976 float hz = 0.125*(squarePoints[i][0][2] + squarePoints[i][2][2] +
977 squarePoints[i][4][2] + squarePoints[i][6][2]);
978
979 /* Extend the inner square to the hole */
980 for (int k=0; k < 4; k++)
981 { //Once per side of the square
982 float p1x = squarePoints[i][(2*k+0)%8][0];
983 float p1y = squarePoints[i][(2*k+0)%8][1];
984 float p1z = squarePoints[i][(2*k+0)%8][2];
985 shiftToHoleBorder(squarePoints[i][(2*k+0)%8][3], &p1x, &p1y, &p1z);
986
987 float p2x = squarePoints[i][(2*k+2)%8][0];
988 float p2y = squarePoints[i][(2*k+2)%8][1];
989 float p2z = squarePoints[i][(2*k+2)%8][2];
990 shiftToHoleBorder(squarePoints[i][(2*k+2)%8][3], &p2x, &p2y, &p2z);
991
992 float p3x = p1x;
993 float p3y = p1y;
994 float p3z = p1z;
995
996 float p4x = p2x;
997 float p4y = p2y;
998 float p4z = p2z;
999
1000 float connectingHoleRadius = 0.5 / par.sphere_rad;
1001
1002 // connectingHoleRadius is a diagonal measurement for square holes.
1003 // Thus, enlarge them by sqrt(2) for a side measurement.
1004 if (par.hole_diam < 0)
1005 connectingHoleRadius *= - (sqrt(2.0) * par.hole_diam);
1006 else
1007 connectingHoleRadius *= par.hole_diam;
1008
1009 shiftToConnectingHole(hx, hy, hz, connectingHoleRadius, &p3x, &p3y, &p3z);
1010 shiftToConnectingHole(hx, hy, hz, connectingHoleRadius, &p4x, &p4y, &p4z);
1011
1012 drawConnectingHole(hx, hy, hz, p1x, p1y, p1z, p2x, p2y, p2z, p3x, p3y, p3z, p4x, p4y, p4z, 3, (int)recursion, par);
1013 }
1014 } // End else
1015 } // End of loop over i
1016 }
1017
curvOk(float curvrad,float cnrad,float sprad,float offset)1018 static bool curvOk(float curvrad, float cnrad, float sprad, float offset)
1019 {
1020 float curvx = cnrad*(sprad-offset)/2+curvrad;
1021 float curvy = sqrt((sprad-offset+curvrad)*(sprad-offset+curvrad)-curvx*curvx);
1022
1023 if (curvy > sprad) return false;
1024 if (curvy/curvx < tan(60*M_PI/180)) return false;
1025
1026 return true;
1027 }
1028
getMeshInternal(float sphere_rad,float connection_rad,float round,float offset,int recursion,float inner_rad,float hole_diam,bool fast) const1029 Polyhedron * voxel_2_c::getMeshInternal(float sphere_rad, float connection_rad, float round, float offset, int recursion, float inner_rad, float hole_diam, bool fast) const
1030 {
1031 Polyhedron * poly = new Polyhedron;
1032 vertexList_c vl(poly);
1033
1034 float maxcurv = 10;
1035 float maxcurv2 = 0;
1036
1037 while (curvOk(maxcurv, connection_rad, sphere_rad, offset))
1038 {
1039 maxcurv2 = maxcurv;
1040 maxcurv *= 2;
1041 }
1042
1043 while (fabs(maxcurv2-maxcurv) > Epsilon)
1044 {
1045 if (curvOk((maxcurv+maxcurv2)/2, connection_rad, sphere_rad, offset))
1046 {
1047 maxcurv2 = (maxcurv+maxcurv2)/2;
1048 }
1049 else
1050 {
1051 maxcurv = (maxcurv+maxcurv2)/2;
1052 }
1053 }
1054
1055 genPar par;
1056
1057 par.sphere_rad = sphere_rad;
1058 par.inner_rad = inner_rad;
1059 par.offset = offset;
1060 par.hole_diam = hole_diam;
1061 par.connection_rad = connection_rad;
1062 par.curvRad = maxcurv * round;
1063 par.curvX = connection_rad*(sphere_rad - offset)/2 + par.curvRad;
1064 par.curvY = sqrt((sphere_rad-offset+par.curvRad)*(sphere_rad-offset+par.curvRad)-par.curvX*par.curvX);
1065 par.vl = &vl;
1066 par.holeStart = atan((par.connection_rad*(par.sphere_rad-par.offset)/2)/par.sphere_rad);
1067 par.lineEnd = M_PI/2-atan2(par.curvY, par.curvX-par.curvRad);
1068 par.curvEnd = M_PI/2-atan2(par.curvY, par.curvX);
1069
1070 if (par.lineEnd < par.holeStart) par.lineEnd = par.holeStart;
1071 if (par.curvEnd < par.lineEnd) par.curvEnd = par.lineEnd;
1072
1073 for (unsigned int x = 0; x < getX(); x++)
1074 for (unsigned int y = 0; y < getY(); y++)
1075 for (unsigned int z = 0; z < getZ(); z++) {
1076 if (validCoordinate(x, y, z) && !isEmpty(x, y, z))
1077 {
1078 /* collect neighbors for a bitmask */
1079 uint16_t neighbors = 0;
1080
1081 int nx, ny, nz;
1082 int idx = 0;
1083
1084 while (getNeighbor(idx, 0, x, y, z, &nx, &ny, &nz))
1085 {
1086 if (validCoordinate(nx, ny, nz) && !isEmpty2(nx, ny, nz))
1087 neighbors |= 1<<idx;
1088 idx++;
1089 }
1090
1091 bool hollow = false;
1092 if (inner_rad > Epsilon) hollow = true;
1093
1094 par.fb_index = getIndex(x, y, z);
1095 bool variable = isVariable(x, y, z);
1096 par.color = getColor(x, y, z);
1097
1098 par.xc = 2*sphere_rad*(x)*sqrt(0.5)+sphere_rad;
1099 par.yc = 2*sphere_rad*(y)*sqrt(0.5)+sphere_rad;
1100 par.zc = 2*sphere_rad*(z)*sqrt(0.5)+sphere_rad;
1101
1102 // Draw the outside of the sphere.
1103 par.outside = true;
1104 makeSphere(neighbors, recursion, hollow, variable, par);
1105
1106 // In the sphere is hollow, draw the inside of the sphere.
1107 // The connection between the inner and outer halves is done with the outside.
1108 if (hollow)
1109 {
1110 par.outside = false;
1111 par.fb_index = 0;
1112 par.flags = false;
1113 makeSphere(neighbors, recursion, hollow, variable, par);
1114 }
1115 }
1116 }
1117
1118 if (!fast)
1119 {
1120 poly->finalize();
1121 }
1122
1123 return poly;
1124 }
1125
getMesh(float sphere_rad,float connection_rad,float round,float offset,int recursion,float inner_rad,float hole_diam) const1126 Polyhedron * voxel_2_c::getMesh(float sphere_rad, float connection_rad, float round, float offset, int recursion, float inner_rad, float hole_diam) const
1127 {
1128 return getMeshInternal(
1129 sphere_rad, connection_rad, round, offset, recursion, inner_rad, hole_diam, false);
1130 }
1131
getDrawingMesh(void) const1132 Polyhedron * voxel_2_c::getDrawingMesh(void) const
1133 {
1134 return getMeshInternal(
1135 0.5, // sphere radius
1136 0.7, // connection radius
1137 1, // round
1138 0.01, // offset
1139 1, // recursion
1140 0, // inner_rad
1141 0, // hole_diam
1142 true // fast generation
1143 );
1144 }
1145
getWireframeMesh(void) const1146 Polyhedron * voxel_2_c::getWireframeMesh(void) const
1147 {
1148 return getDrawingMesh();
1149 }
1150
getConnectionFace(int x,int y,int z,int n,double,double,std::vector<float> & faceCorners) const1151 void voxel_2_c::getConnectionFace(int x, int y, int z, int n, double /*bevel*/, double /*offset*/, std::vector<float> & faceCorners) const
1152 {
1153 static const float A = sqrt(0.5);
1154 static const float B = sqrt(0.125);
1155
1156 /* array of
1157 * - of the 12 neighbors
1158 * - of the 4 points of a rhombus
1159 * - x, y, z
1160 */
1161 static const float faces[12][4][3] =
1162 {
1163 /* neighbor at -1, -1, 0 */ { {0, -A, 0}, {-B, -B, B}, {-A, 0, 0}, {-B, -B, -B} },
1164 /* neighbor at -1, 1, 0 */ { {0, A, 0}, {-B, B, -B}, {-A, 0, 0}, {-B, B, B} },
1165 /* neighbor at 1, -1, 0 */ { {0, -A, 0}, { B, -B, -B}, { A, 0, 0}, { B, -B, B} },
1166 /* neighbor at 1, 1, 0 */ { {0, A, 0}, { B, B, B}, { A, 0, 0}, { B, B, -B} },
1167
1168 /* neighbor at -1, 0, -1 */ { {-A, 0, 0}, {-B, B, -B}, {0, 0, -A}, {-B, -B, -B} },
1169 /* neighbor at -1, 0, 1 */ { {-A, 0, 0}, {-B, -B, B}, {0, 0, A}, {-B, B, B} },
1170 /* neighbor at 1, 0, -1 */ { { A, 0, 0}, { B, -B, -B}, {0, 0, -A}, { B, B, -B} },
1171 /* neighbor at 1, 0, 1 */ { { A, 0, 0}, { B, B, B}, {0, 0, A}, { B, -B, B} },
1172
1173 /* neighbor at 0, -1, -1 */ { {0, 0, -A}, { B, -B, -B}, {0, -A, 0}, {-B, -B, -B} },
1174 /* neighbor at 0, -1, 1 */ { {0, 0, A}, {-B, -B, B}, {0, -A, 0}, { B, -B, B} },
1175 /* neighbor at 0, 1, -1 */ { {0, 0, -A}, {-B, B, -B}, {0, A, 0}, { B, B, -B} },
1176 /* neighbor at 0, 1, 1 */ { {0, 0, A}, { B, B, B}, {0, A, 0}, {-B, B, B} },
1177 };
1178
1179 bt_assert(n < 12);
1180
1181 float xc = x*sqrt(0.5)+0.5;
1182 float yc = y*sqrt(0.5)+0.5;
1183 float zc = z*sqrt(0.5)+0.5;
1184
1185 faceCorners.push_back(xc+faces[n][0][0]);
1186 faceCorners.push_back(yc+faces[n][0][1]);
1187 faceCorners.push_back(zc+faces[n][0][2]);
1188
1189 faceCorners.push_back(xc+faces[n][1][0]);
1190 faceCorners.push_back(yc+faces[n][1][1]);
1191 faceCorners.push_back(zc+faces[n][1][2]);
1192
1193 faceCorners.push_back(xc+faces[n][2][0]);
1194 faceCorners.push_back(yc+faces[n][2][1]);
1195 faceCorners.push_back(zc+faces[n][2][2]);
1196
1197 faceCorners.push_back(xc+faces[n][3][0]);
1198 faceCorners.push_back(yc+faces[n][3][1]);
1199 faceCorners.push_back(zc+faces[n][3][2]);
1200 }
1201
calculateSize(float * x,float * y,float * z) const1202 void voxel_2_c::calculateSize(float * x, float * y, float * z) const
1203 {
1204 *x = 1 + (getX()-1)*sqrt(0.5);
1205 *y = 1 + (getY()-1)*sqrt(0.5);
1206 *z = 1 + (getZ()-1)*sqrt(0.5);
1207 }
1208
recalcSpaceCoordinates(float * x,float * y,float * z) const1209 void voxel_2_c::recalcSpaceCoordinates(float * x, float * y, float * z) const
1210 {
1211 *x = *x * sqrt(0.5);
1212 *y = *y * sqrt(0.5);
1213 *z = *z * sqrt(0.5);
1214 }
1215
1216