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