1 /*
2 * Util.cpp
3 *
4 * Copyright (C) 1999 Stephen F. White
5 * 2004 Wu Qingwei
6 *
7 * This program is free software; you can redistribute it and/or modify
8 * it under the terms of the GNU General Public License as published by
9 * the Free Software Foundation; either version 2 of the License, or
10 * (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 (see the file "COPYING" for details); if
19 * not, write to the Free Software Foundation, Inc., 675 Mass Ave,
20 * Cambridge, MA 02139, USA.
21 */
22
23 /*
24 Util::ConvertLDrawColor2LeoCADColor() based on ConvertColor() in
25 leocad/common/pieceinf.cpp of the LeoCAD 0.75 sources by Leonardo Zide
26
27 LeoCAD uses GNU GENERAL PUBLIC LICENSE Version 2, June 1991,
28 see leocad/docs/COPYING.txt of the LeoCAD source package
29 */
30
31 #include "stdafx.h"
32 #include "Util.h"
33 #include "Matrix.h"
34 #include "DuneApp.h"
35 #include "MyMesh.h"
36 #include "SFVec3f.h"
37 #include "SFBool.h"
38 #include "MFVec3f.h"
39 #include "MFInt32.h"
40 #include "MFColor.h"
41 #include "LdrawDefines.h"
42 #include "NodeTextureCoordinate.h"
43 #include "NodeMultiTextureCoordinate.h"
44 #include "NodeExtrusion.h"
45 #include "NodeTransform.h"
46
47 float boxCorners[8][3] = {
48 { -1.0f, -1.0f, -1.0f },
49 { 1.0f, -1.0f, -1.0f },
50 { 1.0f, 1.0f, -1.0f },
51 { -1.0f, 1.0f, -1.0f },
52 { -1.0f, -1.0f, 1.0f },
53 { -1.0f, 1.0f, 1.0f },
54 { 1.0f, 1.0f, 1.0f },
55 { 1.0f, -1.0f, 1.0f },
56 };
57
58 float boxPolygonCorners[24][3] = {
59 { -1.0f, -1.0f, -1.0f },
60 { 1.0f, -1.0f, -1.0f },
61 { 1.0f, 1.0f, -1.0f },
62 { -1.0f, 1.0f, -1.0f },
63
64 { -1.0f, -1.0f, 1.0f },
65 { -1.0f, 1.0f, 1.0f },
66 { 1.0f, 1.0f, 1.0f },
67 { 1.0f, -1.0f, 1.0f },
68
69 { -1.0f, -1.0f, 1.0f },
70 { -1.0f, -1.0f, -1.0f },
71 { 1.0f, -1.0f, -1.0f },
72 { 1.0f, -1.0f, 1.0f },
73
74 { -1.0f, 1.0f, 1.0f },
75 { 1.0f, 1.0f, -1.0f },
76 { -1.0f, 1.0f, -1.0f },
77 { 1.0f, 1.0f, 1.0f },
78
79
80 { -1.0f, 1.0f, -1.0f },
81 { -1.0f, 1.0f, 1.0f },
82 { -1.0f, -1.0f, 1.0f },
83 { -1.0f, -1.0f, 1.0f },
84
85 { 1.0f, 1.0f, -1.0f },
86 { 1.0f, 1.0f, 1.0f },
87 { 1.0f, -1.0f, 1.0f },
88 { 1.0f, -1.0f, 1.0f },
89 };
90
91
92 int boxIndices[24] = {
93 TLF, BLF, BRF, TRF, // front
94 TRF, BRF, BRB, TRB, // right side
95 TRB, BRB, BLB, TLB, // back
96 TLB, BLB, BLF, TLF, // left side
97 TLB, TLF, TRF, TRB, // top
98 BLF, BLB, BRB, BRF, // bottom
99 };
100
101 float boxNormals[6][3] = {
102 { 0.0f, 0.0f, 1.0f },
103 { 1.0f, 0.0f, 0.0f },
104 { 0.0f, 0.0f, -1.0f },
105 { -1.0f, 0.0f, 0.0f },
106 { 0.0f, 1.0f, 0.0f },
107 { 0.0f, -1.0f, 0.0f },
108 };
109
110 float boxTexCoords[4][2] = {
111 { 1.0f, 1.0f },
112 { 1.0f, 0.0f },
113 { 0.0f, 0.0f },
114 { 0.0f, 1.0f },
115 };
116
117 float spereCorners[6][3] = {
118 { 0.0f, 1.0f, 0.0f },
119 { 0.0f, -1.0f, 0.0f },
120 { -1.0f, 0.0f, 0.0f },
121 { 0.0f, -0.0f, -1.0f },
122 { 1.0f, 0.0f, 0.0f },
123 { 0.0f, 0.0f, 1.0f },
124 };
125
126 float CylinderCorners[6][3] = {
127 { 0.0f, 1.0f, 0.0f },
128 { 0.0f, -1.0f, 0.0f },
129 { -1.0f, 0.0f, 0.0f },
130 { 0.0f, -0.0f, -1.0f },
131 { 1.0f, 0.0f, 0.0f },
132 { 0.0f, 0.0f, 1.0f },
133 };
134
135 float ConeCorners[5][3] = {
136 { 0.0f, 1.0f, 0.0f },
137 { 1.0f, -1.0f, 0.0f },
138 {-1.0f, -1.0f, 0.0f },
139 { 0.0f, -1.0f, 1.0f },
140 { 0.0f, -1.0f, -1.0f }
141 };
142
143 void
printVec3f(Vec3f vec)144 Util::printVec3f(Vec3f vec)
145 {
146 printf("%f %f %f\n", vec.x, vec.y, vec.z);
147 }
148
149 void
printVec3fln(Vec3f vec)150 Util::printVec3fln(Vec3f vec)
151 {
152 printVec3f(vec);
153 printf("\n");
154 }
155
156 void
DrawBox(float sizeX,float sizeY,float sizeZ)157 Util::DrawBox(float sizeX, float sizeY, float sizeZ)
158 {
159 glPushMatrix();
160 glScalef(sizeX, sizeY, sizeZ);
161
162 glEnable(GL_CULL_FACE);
163 for (int i = 0; i < 24; i++) {
164 if (i % 4 == 0)
165 glBegin(GL_POLYGON);
166 glNormal3fv( boxNormals[i / 4] );
167 glTexCoord2fv( boxTexCoords[i % 4] );
168 glVertex3fv( boxPolygonCorners[boxIndices[i]] );
169 if (i % 4 == 3)
170 glEnd();
171 }
172 glPopMatrix();
173 }
174
175 //
176 // IntersectSphere
177 //
178 // intersect a ray in 3-space (x1, y1, z1)->(x2, y2, z2) with a unit sphere
179 // at the origin return the nearest point
180
181 Vec3f
IntersectSphere(float x1,float y1,float z1,float x2,float y2,float z2)182 Util::IntersectSphere(float x1, float y1, float z1, float x2, float y2, float z2)
183 {
184 float i = x2 - x1;
185 float j = y2 - y1;
186 float k = z2 - z1;
187
188 float a = i * i + j * j + k * k;
189 float b = 2 * i * x1 + 2 * j * y1 + 2 * k * z1;
190 float c = x1 * x1 + y1 * y1 + z1 * z1 - 1;
191
192 if (a == 0.0f) return Vec3f(0.0f, 0.0f, 0.0f);
193
194 float t = -b + (float) sqrt(b * b - 4.0f * a * c) / 2.0f * a;
195
196 return Vec3f(x1 + t * i, y1 + t * j, z1 + t * k);
197 }
198
199 //
200 // IntersectLines()
201 //
202 // return "true" if the given 2D lines (x1, y1) - (x2, y2) and
203 // (x3, y3) - (x4, y4) intersect
204 //
205
206 bool
IntersectLines(int x1,int y1,int x2,int y2,int x3,int y3,int x4,int y4)207 Util::IntersectLines(int x1, int y1, int x2, int y2,
208 int x3, int y3, int x4, int y4)
209 {
210 int denom = (x4 - x3) * (y2 - y1) - (y4 - y3) * (x2 - x1);
211 int num = (y3 - y1) * (x2 - x1) - (x3 - x1) * (y2 - y1);
212
213 float p2 = (float) num / (float) denom;
214 float p1;
215 if (x1 != x2) {
216 p1 = (x3 + p2 * (x4 - x3) - x1) / (x2 - x1);
217 } else if (y1 != y2) {
218 p1 = (y3 + p2 * (y4 - y3) - y1) / (y2 - y1);
219 } else {
220 return false;
221 }
222
223 return p1 >= 0.0f && p1 <= 1.0f && p2 >= 0.0f && p2 <= 1.0f;
224 }
225
226 float
grayFromColor(float r,float g,float b)227 Util::grayFromColor(float r, float g, float b)
228 {
229 return (r + g + b) / 3.0;
230 }
231
232 void
myGlColor3f(float r,float g,float b)233 Util::myGlColor3f(float r, float g, float b)
234 {
235 if (TheApp->isAnaglyphStereo()) {
236 float gray = Util::grayFromColor(r, g, b);
237 glColor3f(gray, gray, gray);
238 } else
239 glColor3f(r, g, b);
240
241 }
242
243 void
myGlColor4f(float r,float g,float b,float a)244 Util::myGlColor4f(float r, float g, float b, float a)
245 {
246 if (TheApp->isAnaglyphStereo()) {
247 float gray = Util::grayFromColor(r, g, b);
248 glColor4f(gray, gray, gray, a);
249 } else
250 glColor4f(r, g, b, a);
251
252 }
253
254 void
myGlColor3fv(const float * c)255 Util::myGlColor3fv(const float *c)
256 {
257 if (TheApp->isAnaglyphStereo()) {
258 float gray = Util::grayFromColor(c[0], c[1], c[2]);
259 glColor3f(gray, gray, gray);
260 } else
261 glColor3fv(c);
262
263 }
264
265 void
myGlColor4fv(const float * c)266 Util::myGlColor4fv(const float *c)
267 {
268 if (TheApp->isAnaglyphStereo()) {
269 float gray = Util::grayFromColor(c[0], c[1], c[2]);
270 glColor4f(gray, gray, gray, c[3]);
271 } else
272 glColor4fv(c);
273 }
274
275 bool
need4Colors(GLenum pname)276 Util::need4Colors(GLenum pname)
277 {
278 float need4Colors = false;
279 switch (pname) {
280 case GL_AMBIENT:
281 case GL_DIFFUSE:
282 case GL_SPECULAR:
283 case GL_EMISSION:
284 case GL_AMBIENT_AND_DIFFUSE:
285 need4Colors = true;
286 break;
287 case GL_COLOR_INDEXES:
288 // GL_COLOR_INDEXES not supported yet
289 assert(0);
290 }
291 return need4Colors;
292 }
293
294 void
myGlMaterial3fv(GLenum face,GLenum pname,const float * c)295 Util::myGlMaterial3fv(GLenum face, GLenum pname, const float *c)
296 {
297 bool has4Colors = need4Colors(pname);
298 if (TheApp->isAnaglyphStereo()) {
299 float gray = Util::grayFromColor(c[0], c[1], c[2]);
300 if (has4Colors) {
301 float color[4] = { gray, gray, gray, 1.0f };
302 glMaterialfv(face, pname, color);
303 } else {
304 float color[3] = { gray, gray, gray };
305 glMaterialfv(face, pname, color);
306 }
307 } else {
308 if (has4Colors) {
309 float color[4] = { c[0], c[1], c[2], 1.0f };
310 glMaterialfv(face, pname, color);
311 } else
312 glMaterialfv(face, pname, c);
313 }
314 }
315
316 void
myGlMaterialfv(GLenum face,GLenum pname,const float * c)317 Util::myGlMaterialfv(GLenum face, GLenum pname, const float *c)
318 {
319 bool has4Colors = need4Colors(pname);
320 if (TheApp->isAnaglyphStereo()) {
321 float gray = Util::grayFromColor(c[0], c[1], c[2]);
322 if (has4Colors) {
323 float color[4] = { gray, gray, gray, c[3] };
324 glMaterialfv(face, pname, color);
325 } else {
326 float color[3] = { gray, gray, gray };
327 glMaterialfv(face, pname, color);
328 }
329 } else
330 glMaterialfv(face, pname, c);
331 }
332
333 MyMesh *coneMesh = NULL;
334 MyMesh *coneMeshOnlySide = NULL;
335 MyMesh *coneMeshOnlyBottom = NULL;
336
337 void
createConeMesh(bool cleanDoubleVertices,bool bside,bool bbottom)338 Util::createConeMesh(bool cleanDoubleVertices, bool bside, bool bbottom)
339 {
340 float fradius = 1;
341 float fheight = 1;
342
343 int tess = TheApp->getTessellation();
344 int numPoints = (1 + tess + 1) * 3;
345
346 if (!bside && !bbottom)
347 return;
348
349 float *fpoint = new float[numPoints];
350 float *fnormal = new float[numPoints];
351
352 int offset = 0;
353 fpoint[offset + 0] = 0;
354 fpoint[offset + 1] = -fheight / 2.0f;
355 fpoint[offset + 2] = 0;
356 fnormal[offset + 0] = 0;
357 fnormal[offset + 1] = -1;
358 fnormal[offset + 2] = 0;
359
360 for (int i = 0; i < tess; i++) {
361 float theta = 2.0f * M_PI * i / tess;
362 int offset = (i + 1) * 3;
363 Vec3f point(sin(theta), -fheight / 2.0f, cos(theta));
364 fpoint[offset + 0] = fradius * point.x;
365 fpoint[offset + 1] = point.y;
366 fpoint[offset + 2] = fradius * point.z;
367 point.normalize();
368 fnormal[offset + 0] = point.x;
369 fnormal[offset + 1] = point.y;
370 fnormal[offset + 2] = point.z;
371 }
372
373 offset = (tess + 1) * 3;
374 fpoint[offset + 0] = 0;
375 fpoint[offset + 1] = fheight / 2.0f;
376 fpoint[offset + 2] = 0;
377 fnormal[offset + 0] = 0;
378 fnormal[offset + 1] = 1;
379 fnormal[offset + 2] = 0;
380
381 MyArray<int> icoordIndex;
382 if (bbottom)
383 for (int i = 0; i < tess; i++) {
384 if (i == (tess - 1))
385 icoordIndex.append(1);
386 else
387 icoordIndex.append(1 + i + 1);
388 icoordIndex.append(0);
389 icoordIndex.append(1 + i);
390 icoordIndex.append(-1);
391 }
392 if (bside)
393 for (int i = 0; i < tess; i++) {
394 icoordIndex.append(tess + 1);
395 if (i == (tess - 1))
396 icoordIndex.append(1);
397 else
398 icoordIndex.append(1 + i + 1);
399 icoordIndex.append(1 + i);
400 icoordIndex.append(-1);
401 }
402
403 MFVec3f *coords = new MFVec3f(fpoint, numPoints);
404
405 MFInt32 *coordIndex = new MFInt32((int *)icoordIndex.getData(),
406 icoordIndex.size());
407
408 MFVec3f *normals = new MFVec3f(fnormal, numPoints);
409
410 MFInt32 *normalIndex = NULL;
411
412 MFColor *colors = NULL;
413 MFInt32 *colorIndex = NULL;
414 MyArray<MFVec2f *>texCoords;
415 MFInt32 *texCoordIndex = NULL;
416
417 int meshFlags = MESH_NORMAL_PER_VERTEX;
418
419 MyMesh *mesh = new MyMesh(NULL,
420 coords, coordIndex, normals, normalIndex, colors,
421 colorIndex, texCoords, texCoordIndex,
422 M_PI / 2.0 - 0.0001f, meshFlags, 0);
423 mesh->smoothNormals();
424 if (bside && bbottom) {
425 if (coneMesh)
426 delete coneMesh;
427 coneMesh = mesh;
428 } else if (bside) {
429 if (coneMeshOnlySide)
430 delete coneMeshOnlySide;
431 coneMeshOnlySide = mesh;
432 } else if (bbottom) {
433 if (coneMeshOnlyBottom)
434 delete coneMeshOnlyBottom;
435 coneMeshOnlyBottom = mesh;
436 }
437 }
438
439 void
DrawCone(float radius,float height,bool side,bool bottom,int meshFlags)440 Util::DrawCone(float radius, float height, bool side, bool bottom,
441 int meshFlags)
442 {
443 glPushMatrix();
444 glScalef(radius, height, radius);
445 if (side && bottom) {
446 if (coneMesh == NULL)
447 createConeMesh(false, side, bottom);
448 coneMesh->draw(meshFlags);
449 } else if (side) {
450 if (coneMeshOnlySide == NULL)
451 createConeMesh(false, side, bottom);
452 coneMeshOnlySide->draw(meshFlags);
453 } else if (bottom) {
454 if (coneMeshOnlyBottom == NULL)
455 createConeMesh(false, side, bottom);
456 coneMeshOnlyBottom->draw(meshFlags);
457 }
458 glPopMatrix();
459 }
460
461 struct TableLdrawColorRGBValues {
462 int ldrawColor;
463 float r;
464 float g;
465 float b;
466 float a;
467 bool matchingColorName;
468 };
469
470 // data based on "LDraw.org Color Chart" http://www.ldraw.org/Article93.html
471
472 struct TableLdrawColorRGBValues ldrawColorTable[] = {
473 // please blame the creators of the Ldraw standard for the
474 // magic number problem 8-)
475 { 0, 0.13, 0.13, 0.13, 1, true },
476 { 1, 0.00, 0.20, 0.70, 1, true },
477 { 10, 0.42, 0.93, 0.56, 1, true },
478 { 6, 0.36, 0.13, 0.00, 1, true },
479 { 334, 0.88, 0.43, 0.07, 1, true },
480 { 383, 0.88, 0.88, 0.88, 1, true },
481 { 47, 1.00, 1.00, 1.00, 0.90, true },
482 { 272, 0.00, 0.11, 0.41, 1, true },
483 { 8, 0.39, 0.37, 0.32, 1, true },
484 { 288, 0.15, 0.27, 0.17, 1, true },
485 { 484, 0.70, 0.24, 0.00, 1, true },
486 { 5, 0.87, 0.40, 0.58, 1, true },
487 { 320, 0.47, 0.00, 0.11, 1, true },
488 { 72, 0.39, 0.37, 0.38, 1, true },
489 { 28, 0.77, 0.59, 0.31, 1, false },
490 { 366, 0.82, 0.51, 0.02, 1, true },
491 { 494, 0.82, 0.82, 0.82, 1, false },
492 { 7, 0.76, 0.76, 0.76, 1, true },
493 { 2, 0.00, 0.55, 0.08, 1, true },
494 { 9, 0.42, 0.67, 0.86, 1, true },
495 { 503, 0.90, 0.89, 0.85, 1, true },
496 { 17, 0.73, 1.00, 0.81, 1, true },
497 { 462, 1.00, 0.62, 0.02, 1, true },
498 { 12, 1.00, 0.50, 0.20, 1, true }, // leocad orange, ldraw defines { 12, 1.00, 0.52, 0.48, 1, true }, a rather pink orange
499 { 20, 0.84, 0.77, 0.90, 1, true },
500 { 18, 0.99, 0.91, 0.59, 1, true },
501 { 27, 0.84, 0.94, 0.00, 1, true },
502 { 26, 0.85, 0.11, 0.43, 1, true },
503 { 25, 0.98, 0.38, 0.00, 1, true },
504 { 134, 0.58, 0.53, 0.40, 1, true },
505 { 142, 0.84, 0.66, 0.29, 1, true },
506 { 135, 0.67, 0.68, 0.67, 1, true },
507 { 137, 0.42, 0.48, 0.59, 1, true },
508 { 21, 0.88, 1.00, 0.69, 1, true },
509 { 13, 0.98, 0.64, 0.78, 1, true },
510 { 4, 0.77, 0.00, 0.15, 1, true },
511 { 70, 0.41, 0.25, 0.15, 1, true },
512 { 256, 0.13, 0.13, 0.13, 1, true },
513 { 273, 0.00, 0.20, 0.70, 1, true },
514 { 375, 0.76, 0.76, 0.76, 1, true },
515 { 324, 0.77, 0.00, 0.15, 1, true },
516 { 511, 1.00, 1.00, 1.00, 1, true },
517 { 379, 0.42, 0.48, 0.59, 1, true },
518 { 378, 0.63, 0.74, 0.67, 1, true },
519 { 335, 0.75, 0.53, 0.51, 1, true },
520 { 373, 0.52, 0.37, 0.52, 1, true },
521 { 71, 0.64, 0.64, 0.64, 1, true },
522 { 19, 0.91, 0.81, 0.63, 1, true },
523 { 3, 0.00, 0.60, 0.62, 1, true },
524 { 33, 0.00, 0.13, 0.63, 0.90, true },
525 { 42, 0.75, 1.00, 0.00, 0.90, true },
526 { 57, 0.98, 0.38, 0.00, 0.80, true },
527 { 40, 0.39, 0.37, 0.32, 0.90, true },
528 { 34, 0.02, 0.39, 0.20, 0.90, true },
529 { 41, 0.68, 0.94, 0.93, 0.95, true },
530 { 45, 0.87, 0.40, 0.58, 1, false },
531 { 36, 0.77, 0.00, 0.15, 0.90 , true },
532 { 37, 0.39, 0.00, 0.38, 1, false },
533 { 46, 0.79, 0.69, 0.00, 0.90, true },
534 { 11, 0.20, 0.65, 0.65, 1, true },
535 { 22, 0.51, 0.00, 0.48, 1, true },
536 { 23, 0.28, 0.20, 0.69, 1, true },
537 { 15, 1.00, 1.00, 1.00, 1, true },
538 { 14, 1.00, 0.86, 0.00, 1, true },
539 { 44, 1.00, 0.50, 0.20, 0.90, true } // added: leocad transparent orange
540 };
541
542 // Extracted and modified from common/pieceinf.cpp of LeoCAD 0.75
543 // needed modifications: returntype and all places with "return -1"
544
545 // Convert a color from LDraw to LeoCAD
convertLDrawColor2LeoCADColor(int c)546 static int convertLDrawColor2LeoCADColor(int c)
547 {
548 if (c > 255) c -= 256;
549 switch (c)
550 {
551 // please blame the creator of LeoCAD for the magic number problem 8-)
552 case 0: return 9; // black (black)
553 case 1: return 4; // blue (blue)
554 case 2: return 2; // green (green)
555 case 3: return 5; // dark cyan
556 case 4: return 0; // red (red)
557 case 5: return 11; // magenta
558 case 6: return 10; // brown (brown)
559 case 7: return 22; // gray (gray)
560 case 8: return 8; // dark gray (dark gray)
561 case 9: return 5; // light blue ()
562 case 10: return 3; // light green (light green)
563 case 11: return 5; // cyan (light blue)
564 case 12: return 1; // light red
565 case 13: return 11; // pink (pink)
566 case 14: return 6; // yellow (yellow)
567 case 15: return 7; // white (white)
568 case 16: return -1; // invalid: LC_COL_DEFAULT; // special case
569 case 24: return -1; // invalid: LC_COL_EDGES; // edge
570 case 32: return 9; // black
571 case 33: return 18; // clear blue
572 case 34: return 16; // clear green
573 case 35: return 5; // dark cyan
574 case 36: return 14; // clear red
575 case 37: return 11; // magenta
576 case 38: return 10; // brown
577 case 39: return 21; // clear white (clear gray)
578 case 40: return 8; // dark gray
579 case 41: return 19; // clear light blue
580 case 42: return 17; // clear light green
581 case 43: return 19; // clear cyan (clear light blue)
582 case 44: return 15; // clear light red ??
583 case 45: return 11; // pink
584 case 46: return 20; // clear yellow
585 case 47: return 21; // clear white
586 case 70: return 10; // maroon (326)
587 case 78: return 13; // gold (334)
588 case 110: return 1; // orange (366 from fire logo pattern)
589 case 126: return 23; // tan (382)
590 case 127: return 27; // silver/chrome (383)
591 case 175: return 3; // mint green (431)
592 case 206: return 1; // orange (462)
593 case 238: return 6; // light yellow (494 eletric contacts)
594 case 239: return 6; // light yellow (495)
595 case 247: return 27; // 503 chrome
596 case 250: return 3; // 506 mint (Belville)
597 case 253: return 11; // 509 rose (e.g. in Paradisa)
598
599 // taken from l2p.doc but not verified
600 case 178: return 11; // 434 dark cyan (e.g. in New Technic Models)
601 case 254: return 6; // 510 light yellow (e.g. in Belville)
602 }
603 return -1; // invalid
604 }
605
606 int
getLdrawColorFromRGBA(float r,float g,float b,float a,bool leocad)607 Util::getLdrawColorFromRGBA(float r, float g, float b, float a, bool leocad)
608 {
609 float minError = 4.0f;
610 int ret = LDRAW_CURRENT_COLOR;
611 int tableLength = sizeof(ldrawColorTable) /
612 sizeof(struct TableLdrawColorRGBValues);
613 struct TableLdrawColorRGBValues *table = ldrawColorTable;
614 for (int i = 0; i < tableLength; i++) {
615 if ((a < 1) && (table[i].a == 1))
616 continue;
617 if ((a == 1) && (table[i].a < 1))
618 continue;
619 if (leocad && (!table[i].matchingColorName))
620 continue;
621 if (convertLDrawColor2LeoCADColor(table[i].ldrawColor) == -1)
622 continue;
623 float currentError = (table[i].r - r) * (table[i].r - r) +
624 (table[i].g - g) * (table[i].g - g) +
625 (table[i].b - b) * (table[i].b - b);
626 if (currentError < minError) {
627 ret = table[i].ldrawColor;
628 minError = currentError;
629 }
630 }
631 return ret;
632 }
633
634 bool
invertMatrix(float out[16],const float in[16])635 Util::invertMatrix(float out[16], const float in[16])
636 {
637 float inv[16];
638 float det = 0;
639
640 inv[0] = in[5] * in[10] * in[15] -
641 in[5] * in[11] * in[14] -
642 in[9] * in[6] * in[15] +
643 in[9] * in[7] * in[14] +
644 in[13] * in[6] * in[11] -
645 in[13] * in[7] * in[10];
646
647 inv[4] = -in[4] * in[10] * in[15] +
648 in[4] * in[11] * in[14] +
649 in[8] * in[6] * in[15] -
650 in[8] * in[7] * in[14] -
651 in[12] * in[6] * in[11] +
652 in[12] * in[7] * in[10];
653
654 inv[8] = in[4] * in[9] * in[15] -
655 in[4] * in[11] * in[13] -
656 in[8] * in[5] * in[15] +
657 in[8] * in[7] * in[13] +
658 in[12] * in[5] * in[11] -
659 in[12] * in[7] * in[9];
660
661 inv[12] = -in[4] * in[9] * in[14] +
662 in[4] * in[10] * in[13] +
663 in[8] * in[5] * in[14] -
664 in[8] * in[6] * in[13] -
665 in[12] * in[5] * in[10] +
666 in[12] * in[6] * in[9];
667
668 inv[1] = -in[1] * in[10] * in[15] +
669 in[1] * in[11] * in[14] +
670 in[9] * in[2] * in[15] -
671 in[9] * in[3] * in[14] -
672 in[13] * in[2] * in[11] +
673 in[13] * in[3] * in[10];
674
675 inv[5] = in[0] * in[10] * in[15] -
676 in[0] * in[11] * in[14] -
677 in[8] * in[2] * in[15] +
678 in[8] * in[3] * in[14] +
679 in[12] * in[2] * in[11] -
680 in[12] * in[3] * in[10];
681
682 inv[9] = -in[0] * in[9] * in[15] +
683 in[0] * in[11] * in[13] +
684 in[8] * in[1] * in[15] -
685 in[8] * in[3] * in[13] -
686 in[12] * in[1] * in[11] +
687 in[12] * in[3] * in[9];
688
689 inv[13] = in[0] * in[9] * in[14] -
690 in[0] * in[10] * in[13] -
691 in[8] * in[1] * in[14] +
692 in[8] * in[2] * in[13] +
693 in[12] * in[1] * in[10] -
694 in[12] * in[2] * in[9];
695
696 inv[2] = in[1] * in[6] * in[15] -
697 in[1] * in[7] * in[14] -
698 in[5] * in[2] * in[15] +
699 in[5] * in[3] * in[14] +
700 in[13] * in[2] * in[7] -
701 in[13] * in[3] * in[6];
702
703 inv[6] = -in[0] * in[6] * in[15] +
704 in[0] * in[7] * in[14] +
705 in[4] * in[2] * in[15] -
706 in[4] * in[3] * in[14] -
707 in[12] * in[2] * in[7] +
708 in[12] * in[3] * in[6];
709
710 inv[10] = in[0] * in[5] * in[15] -
711 in[0] * in[7] * in[13] -
712 in[4] * in[1] * in[15] +
713 in[4] * in[3] * in[13] +
714 in[12] * in[1] * in[7] -
715 in[12] * in[3] * in[5];
716
717 inv[14] = -in[0] * in[5] * in[14] +
718 in[0] * in[6] * in[13] +
719 in[4] * in[1] * in[14] -
720 in[4] * in[2] * in[13] -
721 in[12] * in[1] * in[6] +
722 in[12] * in[2] * in[5];
723
724 inv[3] = -in[1] * in[6] * in[11] +
725 in[1] * in[7] * in[10] +
726 in[5] * in[2] * in[11] -
727 in[5] * in[3] * in[10] -
728 in[9] * in[2] * in[7] +
729 in[9] * in[3] * in[6];
730
731 inv[7] = in[0] * in[6] * in[11] -
732 in[0] * in[7] * in[10] -
733 in[4] * in[2] * in[11] +
734 in[4] * in[3] * in[10] +
735 in[8] * in[2] * in[7] -
736 in[8] * in[3] * in[6];
737
738 inv[11] = -in[0] * in[5] * in[11] +
739 in[0] * in[7] * in[9] +
740 in[4] * in[1] * in[11] -
741 in[4] * in[3] * in[9] -
742 in[8] * in[1] * in[7] +
743 in[8] * in[3] * in[5];
744
745 inv[15] = in[0] * in[5] * in[10] -
746 in[0] * in[6] * in[9] -
747 in[4] * in[1] * in[10] +
748 in[4] * in[2] * in[9] +
749 in[8] * in[1] * in[6] -
750 in[8] * in[2] * in[5];
751
752 det = in[0] * inv[0] + in[1] * inv[4] + in[2] * inv[8] + in[3] * inv[12];
753
754 if (det == 0)
755 return false;
756
757 det = 1.0 / det;
758
759 for (int i = 0; i < 16; i++)
760 out[i] = inv[i] * det;
761
762 return true;
763 }
764
765 void
getTexCoords(MyArray<MFVec2f * > & texCoords,Node * texCoord)766 Util::getTexCoords(MyArray<MFVec2f *>&texCoords, Node *texCoord)
767 {
768 MFVec2f *mftexCoord = NULL;
769 if (texCoord) {
770 if (texCoord->getType() == VRML_TEXTURE_COORDINATE) {
771 mftexCoord = ((NodeTextureCoordinate *)texCoord)->point();
772 texCoords.append(mftexCoord);
773 } else if (texCoord->getType() ==
774 X3D_MULTI_TEXTURE_COORDINATE) {
775 NodeMultiTextureCoordinate *multiTexCoord =
776 (NodeMultiTextureCoordinate *)texCoord;
777 for (int i = 0; i < multiTexCoord->texCoord()->getSize(); i++) {
778 if (multiTexCoord->texCoord()->getValue(i)->getType()
779 == VRML_TEXTURE_COORDINATE) {
780 mftexCoord = ((NodeTextureCoordinate *)
781 multiTexCoord->texCoord()->getValue(i))->
782 point();
783 texCoords.append(mftexCoord);
784 }
785 }
786 }
787 }
788 }
789
790 bool
hasExtrusionConvexHull(Scene * scene)791 Util::hasExtrusionConvexHull(Scene *scene)
792 {
793 #ifdef HAVE_LIBCGAL
794 MyArray<Vec3f> *exPoints1 = scene->getStore4ExtrusionConvexHull(1);
795 MyArray<Vec3f> *exPoints2 = scene->getStore4ExtrusionConvexHull(2);
796 if ((exPoints1->size() > 1) && (exPoints2->size() > 1))
797 return true;
798 #endif
799 return false;
800 }
801
802 NodeTransform *
transform4ExtrusionConvexHull(Scene * scene)803 Util::transform4ExtrusionConvexHull(Scene *scene)
804 {
805 Vec3f midPoint = getMidPoint(scene);
806 NodeTransform *transform = (NodeTransform *)
807 scene->createNode("Transform");
808 transform->translation(new SFVec3f(midPoint.x, midPoint.y, midPoint.z));
809 return transform;
810 }
811
812 Vec3f
getMidPoint(Scene * scene)813 Util::getMidPoint(Scene *scene)
814 {
815 Vec3f midPoint;
816 MyArray<Vec3f> *extrusionPoints1 = scene->getStore4ExtrusionConvexHull(1);
817 MyArray<Vec3f> *extrusionPoints2 = scene->getStore4ExtrusionConvexHull(2);
818
819 if (extrusionPoints1->size() == 0 || extrusionPoints2->size() == 0)
820 return NULL;
821
822 Vec3f midPoint1;
823 for (int i = 0; i < extrusionPoints1->size(); i++)
824 midPoint1 = midPoint1 + (Vec3f)extrusionPoints1->get(i);
825 midPoint1 = midPoint1 / extrusionPoints1->size();
826
827 Vec3f midPoint2;
828 for (int i = 0; i < extrusionPoints2->size(); i++)
829 midPoint2 = midPoint2 + (Vec3f)extrusionPoints2->get(i);
830 midPoint2 = midPoint2 * (1.0f / extrusionPoints2->size());
831
832 if (extrusionPoints1->size() > extrusionPoints2->size()) {
833 midPoint = midPoint1;
834 } else {
835 midPoint = midPoint2;
836 }
837 return midPoint;
838 }
839
840 #ifdef HAVE_LIBCGAL
841 #undef max
842 #include "Scene.h"
843 #include "NodeIndexedFaceSet.h"
844
845 #include <CGAL/Exact_predicates_inexact_constructions_kernel.h>
846 #include <CGAL/Polyhedron_3.h>
847 #include <CGAL/Surface_mesh.h>
848 #include <CGAL/convex_hull_3.h>
849 #include <CGAL/Exact_predicates_inexact_constructions_kernel.h>
850 #include <CGAL/convex_hull_2.h>
851 #include <vector>
852
853 typedef CGAL::Exact_predicates_inexact_constructions_kernel K;
854 typedef K::Point_2 Point_2;
855 typedef CGAL::Exact_predicates_inexact_constructions_kernel K;
856 typedef CGAL::Polyhedron_3<K> Polyhedron_3;
857 typedef K::Point_3 Point_3;
858 typedef CGAL::Surface_mesh<Point_3> Surface_mesh;
859 typedef Surface_mesh::Face_index Face_index;
860
861 // workaround a bug in Boost-1.54
862 #include <CGAL/boost/graph/dijkstra_shortest_paths.h>
863 #include <boost/graph/prim_minimum_spanning_tree.hpp>
864 #include <boost/foreach.hpp>
865 typedef boost::graph_traits<Surface_mesh>::vertex_descriptor vertex_descriptor;
866 typedef boost::graph_traits<Surface_mesh>::face_descriptor face_descriptor;
867 typedef boost::graph_traits<Surface_mesh>::halfedge_descriptor halfedge_descriptor;
868
869 NodeExtrusion *
extrusionConvexHull(Scene * scene,int extrusionPoints)870 Util::extrusionConvexHull(Scene *scene, int extrusionPoints)
871 {
872 MyArray<Vec3f> *extrusionPoints1 = scene->getStore4ExtrusionConvexHull(1);
873 MyArray<Vec3f> *extrusionPoints2 = scene->getStore4ExtrusionConvexHull(2);
874
875 if (extrusionPoints1->size() == 0 || extrusionPoints2->size() == 0)
876 return NULL;
877
878 Vec3f midPoint1;
879 for (int i = 0; i < extrusionPoints1->size(); i++)
880 midPoint1 = midPoint1 + (Vec3f)extrusionPoints1->get(i);
881 midPoint1 = midPoint1 / extrusionPoints1->size();
882
883 Vec3f midPoint2;
884 for (int i = 0; i < extrusionPoints2->size(); i++)
885 midPoint2 = midPoint2 + (Vec3f)extrusionPoints2->get(i);
886 midPoint2 = midPoint2 * (1.0f / extrusionPoints2->size());
887
888 MyArray<Vec2f> squareDistance1;
889 for (int i = 0; i < extrusionPoints1->size(); i++) {
890 Vec3f squareDist = extrusionPoints1->get(i).cross(midPoint1) /
891 extrusionPoints1->get(i).length();
892 squareDistance1.append(Vec2f(squareDist.y, squareDist.z));
893 }
894
895 float maxX1 = -FLT_MIN;
896 float maxY1 = -FLT_MIN;
897 for (int i = 0; i < squareDistance1.size(); i++) {
898 if (maxX1 < squareDistance1[i].x)
899 maxX1 = squareDistance1[i].x;
900 if (maxY1 < squareDistance1[i].y)
901 maxY1 = squareDistance1[i].y;
902 }
903
904 MyArray<Vec2f> squareDistance2;
905 for (int i = 0; i < extrusionPoints2->size(); i++) {
906 Vec3f squareDist = extrusionPoints2->get(i).cross(midPoint2) /
907 extrusionPoints2->get(i).length();
908 squareDistance2.append(Vec2f(squareDist.y, squareDist.z));
909 }
910
911 float maxX2 = -FLT_MIN;
912 float maxY2 = -FLT_MIN;
913 for (int i = 0; i < squareDistance2.size(); i++) {
914 if (maxX2 < squareDistance2[i].x)
915 maxX2 = squareDistance2[i].x;
916 if (maxY2 < squareDistance2[i].y)
917 maxY2 = squareDistance2[i].y;
918 }
919
920 int resultSize = -1;
921 Point_2 *result = NULL;
922 Vec3f midPoint;
923 Vec3f spine;
924 float maxXex;
925 float maxYex;
926 float maxX;
927 float maxY;
928 if (extrusionPoints1->size() > extrusionPoints2->size()) {
929 MyArray<Point_2> squarePoint1;
930 for (int i = 0; i < squareDistance1.size(); i++)
931 squarePoint1.append(Point_2(squareDistance1.get(i).x,
932 squareDistance1.get(i).y));
933 result = new Point_2[squarePoint1.size()];
934 Point_2 *ptr = CGAL::convex_hull_2(squarePoint1.getData(),
935 squarePoint1.getData() + squarePoint1.size(), result);
936 resultSize = ptr - result;
937 midPoint = midPoint1;
938 spine = midPoint2 - midPoint1;
939 spine = spine * 1.2f / (float)extrusionPoints;
940 maxXex = maxX1;
941 maxYex = maxY1;
942 maxX = maxX2;
943 maxY = maxY2;
944 } else {
945 MyArray<Point_2> squarePoint2;
946 for (int i = 0; i < squareDistance2.size(); i++)
947 squarePoint2.append(Point_2(squareDistance2.get(i).x,
948 squareDistance2.get(i).y));
949 Point_2 *result = new Point_2[squarePoint2.size()];
950 Point_2 *ptr = CGAL::convex_hull_2(squarePoint2.getData(),
951 squarePoint2.getData() + squarePoint2.size(), result);
952 resultSize = ptr - result;
953 midPoint = midPoint2;
954 spine = midPoint1 - midPoint2;
955 spine = spine * 1.2f * (float)extrusionPoints;
956 maxXex = maxX2;
957 maxYex = maxY2;
958 maxX = maxX1;
959 maxY = maxY1;
960 }
961
962 if (result == NULL)
963 return NULL;
964
965 MFVec2f *crossPoints = new MFVec2f();
966 crossPoints->appendSFValue(result[0].x(), result[0].y());
967 for (int i = resultSize - 1; i > -1; i--)
968 crossPoints->appendSFValue(result[i].x(), result[i].y());
969
970 delete [] result;
971
972 Quaternion quat(spine, 1.57);
973 MFVec3f *spinePoints = new MFVec3f();
974 for (int i = 0; i < extrusionPoints; i++) {
975 spinePoints->appendVec(spine * quat * i);
976 }
977
978 MFVec2f *scalePoints = new MFVec2f();
979 for (int i = 0; i < extrusionPoints; i++) {
980 scalePoints->appendSFValue(maxXex + (maxXex - maxX) * i,
981 maxYex + (maxYex - maxY) * i);
982 }
983
984 MFRotation *rot = new MFRotation();
985 SFRotation val(0, 0, 1, 0);
986 rot->insertSFValue(0, &val);
987
988 NodeExtrusion *extrusion = (NodeExtrusion *)
989 scene->createNode("Extrusion");
990 extrusion->crossSection(crossPoints);
991 extrusion->spine(spinePoints);
992 // extrusion->scale(scalePoints);
993 extrusion->orientation(rot);
994 extrusion->creaseAngle(new SFFloat(1.57));
995 extrusion->solid(new SFBool(false));
996
997 return extrusion;
998 }
999
1000 NodeIndexedFaceSet *
convexHull(Scene * scene,MyArray<Vec3f> vec)1001 Util::convexHull(Scene *scene, MyArray<Vec3f> vec)
1002 {
1003 int diffentVecCount = 0;
1004 for (long i = 0; i < vec.size(); i++) {
1005 for (long j = i + 1; j < vec.size(); j++) {
1006 if ((vec[i] - vec[j]).length() != 0)
1007 diffentVecCount++;
1008 if (diffentVecCount > 3)
1009 break;
1010 }
1011 }
1012 if (diffentVecCount <= 3)
1013 return NULL;
1014
1015 std::vector<Point_3> points;
1016 Point_3 p;
1017 for (long i = 0; i < vec.size(); i++) {
1018 Point_3 p(vec[i].x, vec[i].y, vec[i].z);
1019 points.push_back(p);
1020 }
1021 // compute convex hull of non-collinear points
1022 Surface_mesh poly;
1023 CGAL::convex_hull_3(points.begin(), points.end(), poly);
1024
1025 NodeCoordinate *ncoord = (NodeCoordinate *)
1026 scene->createNode("Coordinate");
1027 NodeIndexedFaceSet *faceSet = (NodeIndexedFaceSet *)
1028 scene->createNode("IndexedFaceSet");
1029 faceSet->coord(new SFNode(ncoord));
1030
1031 MFVec3f *newVertices = new MFVec3f();
1032 MFInt32 *newCoordIndex = new MFInt32();
1033
1034 BOOST_FOREACH(vertex_descriptor vd, vertices(poly)){
1035 newVertices->appendSFValue(poly.point(vd).x(),
1036 poly.point(vd).y(),
1037 poly.point(vd).z());
1038 }
1039 BOOST_FOREACH(face_descriptor fd, faces(poly)) {
1040 Surface_mesh::Halfedge_index hf = poly.halfedge(fd);
1041 BOOST_FOREACH(halfedge_descriptor hi, halfedges_around_face(hf,poly)) {
1042 Surface_mesh::Vertex_index vi = target(hi, poly);
1043 newCoordIndex->appendSFValue((std::size_t)vi);
1044 }
1045 newCoordIndex->appendSFValue(-1);
1046 }
1047 ncoord->point(new MFVec3f(newVertices));
1048 faceSet->coordIndex(new MFInt32(newCoordIndex));
1049 return faceSet;
1050 }
1051 #endif
1052
1053
1054