KiCad PCB EDA Suite
Loading...
Searching...
No Matches
vrml_layer.cpp
Go to the documentation of this file.
1/*
2 * file: vrml_layer.cpp
3 *
4 * This program source code file is part of KiCad, a free EDA CAD application.
5 * Copyright The KiCad Developers, see AUTHORS.txt for contributors.
6 *
7 * Copyright (C) 2013-2017 Cirilo Bernardo
8 *
9 * This program is free software; you can redistribute it and/or
10 * modify it under the terms of the GNU General Public License
11 * as published by the Free Software Foundation; either version 2
12 * of the License, or (at your option) any later version.
13 *
14 * This program is distributed in the hope that it will be useful,
15 * but WITHOUT ANY WARRANTY; without even the implied warranty of
16 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
17 * GNU General Public License for more details.
18 *
19 * You should have received a copy of the GNU General Public License
20 * along with this program. If not, see <https://www.gnu.org/licenses/>.
21 */
22
23// Wishlist:
24// 1. crop anything outside the board outline on PTH, silk, and copper layers
25// 2. on the PTH layer, handle cropped holes differently from others;
26// these are assumed to be castellated edges and the profile is not
27// a closed loop as assumed for all other outlines.
28// 3. a scheme is needed to tell a castellated edge from a plain board edge
29
30#include <kicad_gl/kiglu.h>
31
32#include <sstream>
33#include <string>
34#include <iomanip>
35#include <cmath>
36#include <io/idf/vrml_layer.h>
37#include <trigo.h>
38
39#ifndef CALLBACK
40#define CALLBACK
41#endif
42
43#define GLCALLBACK(x) (( void (CALLBACK*)() )&(x))
44
45// minimum sides to a circle
46#define MIN_NSIDES 6
47
48static void FormatDoublet( double x, double y, int precision, std::string& strx, std::string& stry )
49{
50 std::ostringstream ostr;
51
52 ostr << std::fixed << std::setprecision( precision );
53
54 ostr << x;
55 strx = ostr.str();
56
57 ostr.str( "" );
58 ostr << y;
59 stry = ostr.str();
60
61 while( *strx.rbegin() == '0' )
62 strx.erase( strx.size() - 1 );
63
64 while( *stry.rbegin() == '0' )
65 stry.erase( stry.size() - 1 );
66}
67
68
69static void FormatSinglet( double x, int precision, std::string& strx )
70{
71 std::ostringstream ostr;
72
73 ostr << std::fixed << std::setprecision( precision );
74
75 ostr << x;
76 strx = ostr.str();
77
78 while( *strx.rbegin() == '0' )
79 strx.erase( strx.size() - 1 );
80}
81
82
83int VRML_LAYER::calcNSides( double aRadius, double aAngle )
84{
85 // check #segments on ends of arc
86 int maxSeg = maxArcSeg * aAngle / M_PI;
87
88 if( maxSeg < 3 )
89 maxSeg = 3;
90
91 int csides = aRadius * M_PI / minSegLength;
92
93 if( csides < 0 )
94 csides = -csides;
95
96 if( csides > maxSeg )
97 {
98 if( csides < 2 * maxSeg )
99 csides /= 2;
100 else
101 csides = ( ( (double) csides ) * minSegLength / maxSegLength );
102 }
103
104 if( csides < 3 )
105 csides = 3;
106
107 if( ( csides & 1 ) == 0 )
108 csides += 1;
109
110 return csides;
111}
112
113
114static void CALLBACK vrml_tess_begin( GLenum cmd, void* user_data )
115{
116 VRML_LAYER* lp = (VRML_LAYER*) user_data;
117
118 lp->glStart( cmd );
119}
120
121
122static void CALLBACK vrml_tess_end( void* user_data )
123{
124 VRML_LAYER* lp = (VRML_LAYER*) user_data;
125
126 lp->glEnd();
127}
128
129
130static void CALLBACK vrml_tess_vertex( void* vertex_data, void* user_data )
131{
132 VRML_LAYER* lp = (VRML_LAYER*) user_data;
133
134 lp->glPushVertex( (VERTEX_3D*) vertex_data );
135}
136
137
138static void CALLBACK vrml_tess_err( GLenum errorID, void* user_data )
139{
140 VRML_LAYER* lp = (VRML_LAYER*) user_data;
141
142 lp->Fault = true;
143 lp->SetGLError( errorID );
144}
145
146
147static void CALLBACK vrml_tess_combine( GLdouble coords[3], VERTEX_3D* vertex_data[4],
148 GLfloat weight[4], void** outData, void* user_data )
149{
150 VRML_LAYER* lp = (VRML_LAYER*) user_data;
151
152 // the plating is set to true only if all are plated
153 bool plated = vertex_data[0]->pth;
154
155 if( !vertex_data[1]->pth )
156 plated = false;
157
158 if( vertex_data[2] && !vertex_data[2]->pth )
159 plated = false;
160
161 if( vertex_data[3] && !vertex_data[3]->pth )
162 plated = false;
163
164 *outData = lp->AddExtraVertex( coords[0], coords[1], plated );
165}
166
167
169{
171 offsetX = 0.0;
172 offsetY = 0.0;
173
174 fix = false;
175 Fault = false;
176 idx = 0;
177 hidx = 0;
178 eidx = 0;
179 ord = 0;
180 glcmd = 0;
181 pholes = NULL;
182
183 tess = gluNewTess();
184
185 if( !tess )
186 return;
187
188 // set up the tesselator callbacks
189 gluTessCallback( tess, GLU_TESS_BEGIN_DATA, GLCALLBACK( vrml_tess_begin ) );
190
191 gluTessCallback( tess, GLU_TESS_VERTEX_DATA, GLCALLBACK( vrml_tess_vertex ) );
192
193 gluTessCallback( tess, GLU_TESS_END_DATA, GLCALLBACK( vrml_tess_end ) );
194
195 gluTessCallback( tess, GLU_TESS_ERROR_DATA, GLCALLBACK( vrml_tess_err ) );
196
197 gluTessCallback( tess, GLU_TESS_COMBINE_DATA, GLCALLBACK( vrml_tess_combine ) );
198
199 gluTessProperty( tess, GLU_TESS_WINDING_RULE, GLU_TESS_WINDING_POSITIVE );
200
201 gluTessNormal( tess, 0, 0, 1 );
202}
203
204
206{
207 Clear();
208
209 if( tess )
210 {
211 gluDeleteTess( tess );
212 tess = NULL;
213 }
214}
215
216
218{
219 // arc parameters suitable to mm measurements
220 maxArcSeg = 48;
221 minSegLength = 0.1;
222 maxSegLength = 0.5;
223}
224
225
226void VRML_LAYER::GetArcParams( int& aMaxSeg, double& aMinLength, double& aMaxLength )
227{
228 aMaxSeg = maxArcSeg;
229 aMinLength = minSegLength;
230 aMaxLength = maxSegLength;
231}
232
233
234bool VRML_LAYER::SetArcParams( int aMaxSeg, double aMinLength, double aMaxLength )
235{
236 if( aMaxSeg < 8 )
237 aMaxSeg = 8;
238
239 if( aMinLength <= 0 || aMaxLength <= aMinLength )
240 return false;
241
242 maxArcSeg = aMaxSeg;
243 minSegLength = aMinLength;
244 maxSegLength = aMaxLength;
245 return true;
246}
247
248
250{
251 int i;
252
253 fix = false;
254 idx = 0;
255
256 for( i = contours.size(); i > 0; --i )
257 {
258 delete contours.back();
259 contours.pop_back();
260 }
261
262 pth.clear();
263
264 areas.clear();
265
266 for( i = vertices.size(); i > 0; --i )
267 {
268 delete vertices.back();
269 vertices.pop_back();
270 }
271
272 clearTmp();
273}
274
275
277{
278 unsigned int i;
279
280 Fault = false;
281 hidx = 0;
282 eidx = 0;
283 ord = 0;
284 glcmd = 0;
285
286 triplets.clear();
287 solid.clear();
288
289 for( i = outline.size(); i > 0; --i )
290 {
291 delete outline.back();
292 outline.pop_back();
293 }
294
295 ordmap.clear();
296
297 for( i = extra_verts.size(); i > 0; --i )
298 {
299 delete extra_verts.back();
300 extra_verts.pop_back();
301 }
302
303 // note: unlike outline and extra_verts,
304 // vlist is not responsible for memory management
305 vlist.clear();
306
307 // go through the vertex list and reset ephemeral parameters
308 for( i = 0; i < vertices.size(); ++i )
309 {
310 vertices[i]->o = -1;
311 }
312}
313
314
315int VRML_LAYER::NewContour( bool aPlatedHole )
316{
317 if( fix )
318 return -1;
319
320 std::list<int>* contour = new std::list<int>;
321
322 contours.push_back( contour );
323 areas.push_back( 0.0 );
324
325 pth.push_back( aPlatedHole );
326
327 return contours.size() - 1;
328}
329
330
331bool VRML_LAYER::AddVertex( int aContourID, double aXpos, double aYpos )
332{
333 if( fix )
334 {
335 error = "AddVertex(): no more vertices may be added (Tesselate was previously executed)";
336 return false;
337 }
338
339 if( aContourID < 0 || (unsigned int) aContourID >= contours.size() )
340 {
341 error = "AddVertex(): aContour is not within a valid range";
342 return false;
343 }
344
345 VERTEX_3D* vertex = new VERTEX_3D;
346 vertex->x = aXpos;
347 vertex->y = aYpos;
348 vertex->i = idx++;
349 vertex->o = -1;
350 vertex->pth = pth[ aContourID ];
351
352 VERTEX_3D* v2 = NULL;
353
354 if( contours[aContourID]->size() > 0 )
355 v2 = vertices[ contours[aContourID]->back() ];
356
357 vertices.push_back( vertex );
358 contours[aContourID]->push_back( vertex->i );
359
360 if( v2 )
361 areas[aContourID] += ( aXpos - v2->x ) * ( aYpos + v2->y );
362
363 return true;
364}
365
366
367bool VRML_LAYER::EnsureWinding( int aContourID, bool aHoleFlag )
368{
369 if( aContourID < 0 || (unsigned int) aContourID >= contours.size() )
370 {
371 error = "EnsureWinding(): aContour is outside the valid range";
372 return false;
373 }
374
375 std::list<int>* cp = contours[aContourID];
376
377 if( cp->size() < 3 )
378 {
379 error = "EnsureWinding(): there are fewer than 3 vertices";
380 return false;
381 }
382
383 double dir = areas[aContourID];
384
385 VERTEX_3D* vp0 = vertices[ cp->back() ];
386 VERTEX_3D* vp1 = vertices[ cp->front() ];
387
388 dir += ( vp1->x - vp0->x ) * ( vp1->y + vp0->y );
389
390 // if dir is positive, winding is CW
391 if( ( aHoleFlag && dir < 0 ) || ( !aHoleFlag && dir > 0 ) )
392 {
393 cp->reverse();
394 areas[aContourID] = -areas[aContourID];
395 }
396
397 return true;
398}
399
400
401bool VRML_LAYER::AppendCircle( double aXpos, double aYpos, double aRadius, int aContourID,
402 bool aHoleFlag )
403{
404 if( aContourID < 0 || (unsigned int) aContourID >= contours.size() )
405 {
406 error = "AppendCircle(): invalid contour (out of range)";
407 return false;
408 }
409
410 int nsides = M_PI * 2.0 * aRadius / minSegLength;
411
412 if( nsides > maxArcSeg )
413 {
414 if( nsides > 2 * maxArcSeg )
415 {
416 // use segments approx. maxAr
417 nsides = M_PI * 2.0 * aRadius / maxSegLength;
418 }
419 else
420 {
421 nsides /= 2;
422 }
423 }
424
425 if( nsides < MIN_NSIDES )
426 nsides = MIN_NSIDES;
427
428 // even numbers give prettier results for circles
429 if( nsides & 1 )
430 nsides += 1;
431
432 double da = M_PI * 2.0 / nsides;
433
434 bool fail = false;
435
436 if( aHoleFlag )
437 {
438 fail |= !AddVertex( aContourID, aXpos + aRadius, aYpos );
439
440 for( double angle = da; angle < M_PI * 2; angle += da )
441 {
442 fail |= !AddVertex( aContourID, aXpos + aRadius * cos( angle ),
443 aYpos - aRadius * sin( angle ) );
444 }
445 }
446 else
447 {
448 fail |= !AddVertex( aContourID, aXpos + aRadius, aYpos );
449
450 for( double angle = da; angle < M_PI * 2; angle += da )
451 {
452 fail |= !AddVertex( aContourID, aXpos + aRadius * cos( angle ),
453 aYpos + aRadius * sin( angle ) );
454 }
455 }
456
457 return !fail;
458}
459
460
461bool VRML_LAYER::AddCircle( double aXpos, double aYpos, double aRadius, bool aHoleFlag,
462 bool aPlatedHole )
463{
464 int pad;
465
466 if( aHoleFlag && aPlatedHole )
467 pad = NewContour( true );
468 else
469 pad = NewContour( false );
470
471 if( pad < 0 )
472 {
473 error = "AddCircle(): failed to add a contour";
474 return false;
475 }
476
477 return AppendCircle( aXpos, aYpos, aRadius, pad, aHoleFlag );
478}
479
480
481bool VRML_LAYER::AddSlot( double aCenterX, double aCenterY, double aSlotLength, double aSlotWidth,
482 double aAngle, bool aHoleFlag, bool aPlatedHole )
483{
484 aAngle *= M_PI / 180.0;
485
486 if( aSlotWidth > aSlotLength )
487 {
488 aAngle += M_PI2;
489 std::swap( aSlotLength, aSlotWidth );
490 }
491
492 aSlotWidth /= 2.0;
493 aSlotLength = aSlotLength / 2.0 - aSlotWidth;
494
495 int csides = calcNSides( aSlotWidth, M_PI );
496
497 double capx, capy;
498
499 capx = aCenterX + cos( aAngle ) * aSlotLength;
500 capy = aCenterY + sin( aAngle ) * aSlotLength;
501
502 double ang, da;
503 int i;
504 int pad;
505
506 if( aHoleFlag && aPlatedHole )
507 pad = NewContour( true );
508 else
509 pad = NewContour( false );
510
511 if( pad < 0 )
512 {
513 error = "AddCircle(): failed to add a contour";
514 return false;
515 }
516
517 da = M_PI / csides;
518 bool fail = false;
519
520 if( aHoleFlag )
521 {
522 for( ang = aAngle + M_PI2, i = 0; i < csides; ang -= da, ++i )
523 fail |= !AddVertex( pad, capx + aSlotWidth * cos( ang ),
524 capy + aSlotWidth * sin( ang ) );
525
526 ang = aAngle - M_PI2;
527 fail |= !AddVertex( pad, capx + aSlotWidth * cos( ang ),
528 capy + aSlotWidth * sin( ang ) );
529
530 capx = aCenterX - cos( aAngle ) * aSlotLength;
531 capy = aCenterY - sin( aAngle ) * aSlotLength;
532
533 for( ang = aAngle - M_PI2, i = 0; i < csides; ang -= da, ++i )
534 fail |= !AddVertex( pad, capx + aSlotWidth * cos( ang ),
535 capy + aSlotWidth * sin( ang ) );
536
537 ang = aAngle + M_PI2;
538 fail |= !AddVertex( pad, capx + aSlotWidth * cos( ang ),
539 capy + aSlotWidth * sin( ang ) );
540 }
541 else
542 {
543 for( ang = aAngle - M_PI2, i = 0; i < csides; ang += da, ++i )
544 fail |= !AddVertex( pad, capx + aSlotWidth * cos( ang ),
545 capy + aSlotWidth * sin( ang ) );
546
547 ang = aAngle + M_PI2;
548 fail |= !AddVertex( pad, capx + aSlotWidth * cos( ang ),
549 capy + aSlotWidth * sin( ang ) );
550
551 capx = aCenterX - cos( aAngle ) * aSlotLength;
552 capy = aCenterY - sin( aAngle ) * aSlotLength;
553
554 for( ang = aAngle + M_PI2, i = 0; i < csides; ang += da, ++i )
555 fail |= !AddVertex( pad, capx + aSlotWidth * cos( ang ),
556 capy + aSlotWidth * sin( ang ) );
557
558 ang = aAngle - M_PI2;
559 fail |= !AddVertex( pad, capx + aSlotWidth * cos( ang ),
560 capy + aSlotWidth * sin( ang ) );
561 }
562
563 return !fail;
564}
565
566
567bool VRML_LAYER::AddPolygon( const std::vector< wxRealPoint >& aPolySet, double aCenterX,
568 double aCenterY, double aAngle )
569{
570 int pad = NewContour( false );
571
572 if( pad < 0 )
573 {
574 error = "AddPolygon(): failed to add a contour";
575 return false;
576 }
577
578 for( auto corner : aPolySet )
579 {
580 // The sense of polygon rotations is reversed
581 RotatePoint( &corner.x, &corner.y, -EDA_ANGLE( aAngle, DEGREES_T ) );
582 AddVertex( pad, aCenterX + corner.x, aCenterY + corner.y );
583 }
584
585 if( !EnsureWinding( pad, false ) )
586 return false;
587
588 return true;
589}
590
591
592// adds an arc to the given center, start point, pen width, and angle (degrees).
593bool VRML_LAYER::AppendArc( double aCenterX, double aCenterY, double aRadius,
594 double aStartAngle, double aAngle, int aContourID )
595{
596 if( aContourID < 0 || (unsigned int) aContourID >= contours.size() )
597 {
598 error = "AppendArc(): invalid contour (out of range)";
599 return false;
600 }
601
602 aAngle = aAngle / 180.0 * M_PI;
603 aStartAngle = aStartAngle / 180.0 * M_PI;
604
605 int nsides = calcNSides( aRadius, aAngle );
606
607 double da = aAngle / nsides;
608
609 bool fail = false;
610
611 if( aAngle > 0 )
612 {
613 aAngle += aStartAngle;
614
615 for( double ang = aStartAngle; ang < aAngle; ang += da )
616 {
617 fail |= !AddVertex( aContourID, aCenterX + aRadius * cos( ang ),
618 aCenterY + aRadius * sin( ang ) );
619 }
620 }
621 else
622 {
623 aAngle += aStartAngle;
624
625 for( double ang = aStartAngle; ang > aAngle; ang += da )
626 {
627 fail |= !AddVertex( aContourID, aCenterX + aRadius * cos( ang ),
628 aCenterY + aRadius * sin( ang ) );
629 }
630 }
631
632 return !fail;
633}
634
635
636bool VRML_LAYER::AddArc( double aCenterX, double aCenterY, double aStartX, double aStartY,
637 double aArcWidth, double aAngle, bool aHoleFlag, bool aPlatedHole )
638{
639 aAngle *= M_PI / 180.0;
640
641 // we don't accept small angles; in fact, 1 degree ( 0.01745 ) is already
642 // way too small but we must set a limit somewhere
643 if( aAngle < 0.01745 && aAngle > -0.01745 )
644 {
645 error = "AddArc(): angle is too small: abs( angle ) < 1 degree";
646 return false;
647 }
648
649 double rad = sqrt( (aStartX - aCenterX) * (aStartX - aCenterX)
650 + (aStartY - aCenterY) * (aStartY - aCenterY) );
651
652 aArcWidth /= 2.0; // this is the radius of the caps
653
654 // we will not accept an arc with an inner radius close to zero so we
655 // set a limit here. the end result will vary somewhat depending on
656 // the output units
657 if( aArcWidth >= ( rad * 1.01 ) )
658 {
659 error = "AddArc(): width/2 exceeds radius*1.01";
660 return false;
661 }
662
663 // calculate the radii of the outer and inner arcs
664 double orad = rad + aArcWidth;
665 double irad = rad - aArcWidth;
666
667 int osides = calcNSides( orad, aAngle );
668 int isides = calcNSides( irad, aAngle );
669 int csides = calcNSides( aArcWidth, M_PI );
670
671 double stAngle = atan2( aStartY - aCenterY, aStartX - aCenterX );
672 double endAngle = stAngle + aAngle;
673
674 // calculate ends of inner and outer arc
675 double oendx = aCenterX + orad* cos( endAngle );
676 double oendy = aCenterY + orad* sin( endAngle );
677 double ostx = aCenterX + orad* cos( stAngle );
678 double osty = aCenterY + orad* sin( stAngle );
679
680 double iendx = aCenterX + irad* cos( endAngle );
681 double iendy = aCenterY + irad* sin( endAngle );
682 double istx = aCenterX + irad* cos( stAngle );
683 double isty = aCenterY + irad* sin( stAngle );
684
685 if( ( aAngle < 0 && !aHoleFlag ) || ( aAngle > 0 && aHoleFlag ) )
686 {
687 aAngle = -aAngle;
688 std::swap( stAngle, endAngle );
689 std::swap( oendx, ostx );
690 std::swap( oendy, osty );
691 std::swap( iendx, istx );
692 std::swap( iendy, isty );
693 }
694
695 int arc;
696
697 if( aHoleFlag && aPlatedHole )
698 arc = NewContour( true );
699 else
700 arc = NewContour( false );
701
702 if( arc < 0 )
703 {
704 error = "AddArc(): could not create a contour";
705 return false;
706 }
707
708 // trace the outer arc:
709 int i;
710 double ang;
711 double da = aAngle / osides;
712
713 for( ang = stAngle, i = 0; i < osides; ang += da, ++i )
714 AddVertex( arc, aCenterX + orad * cos( ang ), aCenterY + orad * sin( ang ) );
715
716 // trace the first cap
717 double capx = ( iendx + oendx ) / 2.0;
718 double capy = ( iendy + oendy ) / 2.0;
719
720 if( aHoleFlag )
721 da = -M_PI / csides;
722 else
723 da = M_PI / csides;
724
725 for( ang = endAngle, i = 0; i < csides; ang += da, ++i )
726 AddVertex( arc, capx + aArcWidth * cos( ang ), capy + aArcWidth * sin( ang ) );
727
728 // trace the inner arc:
729 da = -aAngle / isides;
730
731 for( ang = endAngle, i = 0; i < isides; ang += da, ++i )
732 AddVertex( arc, aCenterX + irad * cos( ang ), aCenterY + irad * sin( ang ) );
733
734 // trace the final cap
735 capx = ( istx + ostx ) / 2.0;
736 capy = ( isty + osty ) / 2.0;
737
738 if( aHoleFlag )
739 da = -M_PI / csides;
740 else
741 da = M_PI / csides;
742
743 for( ang = stAngle + M_PI, i = 0; i < csides; ang += da, ++i )
744 AddVertex( arc, capx + aArcWidth * cos( ang ), capy + aArcWidth * sin( ang ) );
745
746 return true;
747}
748
749
750bool VRML_LAYER::Tesselate( VRML_LAYER* holes, bool aHolesOnly )
751{
752 if( !tess )
753 {
754 error = "Tesselate(): GLU tesselator was not initialized";
755 return false;
756 }
757
758 pholes = holes;
759 Fault = false;
760
761 if( aHolesOnly )
762 gluTessProperty( tess, GLU_TESS_WINDING_RULE, GLU_TESS_WINDING_NEGATIVE );
763 else
764 gluTessProperty( tess, GLU_TESS_WINDING_RULE, GLU_TESS_WINDING_POSITIVE );
765
766
767 if( contours.size() < 1 || vertices.size() < 3 )
768 {
769 error = "Tesselate(): not enough vertices";
770 return false;
771 }
772
773 // finish the winding calculation on all vertices prior to setting 'fix'
774 if( !fix )
775 {
776 for( unsigned int i = 0; i < contours.size(); ++i )
777 {
778 if( contours[i]->size() < 3 )
779 continue;
780
781 VERTEX_3D* vp0 = vertices[ contours[i]->back() ];
782 VERTEX_3D* vp1 = vertices[ contours[i]->front() ];
783 areas[i] += ( vp1->x - vp0->x ) * ( vp1->y + vp0->y );
784 }
785 }
786
787 // prevent the addition of any further contours and contour vertices
788 fix = true;
789
790 // clear temporary internals which may have been used in a previous run
791 clearTmp();
792
793 // request an outline
794 gluTessProperty( tess, GLU_TESS_BOUNDARY_ONLY, GL_TRUE );
795
796 // adjust internal indices for extra points and holes
797 if( holes )
798 hidx = holes->GetSize();
799 else
800 hidx = 0;
801
802 eidx = idx + hidx;
803
804 if( aHolesOnly && ( checkNContours( true ) == 0 ) )
805 {
806 error = "tesselate(): no hole contours";
807 return false;
808 }
809 else if( !aHolesOnly && ( checkNContours( false ) == 0 ) )
810 {
811 error = "tesselate(): no solid contours";
812 return false;
813 }
814
815 // open the polygon
816 gluTessBeginPolygon( tess, this );
817
818 if( aHolesOnly )
819 {
820 pholes = NULL; // do not accept foreign holes
821 hidx = 0;
822 eidx = idx;
823
824 // add holes
825 pushVertices( true );
826
827 gluTessEndPolygon( tess );
828
829 if( Fault )
830 return false;
831
832 return true;
833 }
834
835 // add solid outlines
836 pushVertices( false );
837
838 // close the polygon
839 gluTessEndPolygon( tess );
840
841 if( Fault )
842 return false;
843
844 // if there are no outlines we cannot proceed
845 if( outline.empty() )
846 {
847 error = "tesselate(): no points in result";
848 return false;
849 }
850
851 // at this point we have a solid outline; add it to the tesselator
852 gluTessBeginPolygon( tess, this );
853
854 if( !pushOutline( NULL ) )
855 return false;
856
857 // add the holes contained by this object
858 pushVertices( true );
859
860 // import external holes (if any)
861 if( hidx && ( holes->Import( idx, tess ) < 0 ) )
862 {
863 std::ostringstream ostr;
864 ostr << "Tesselate():FAILED: " << holes->GetError();
865 error = ostr.str();
866 return false;
867 }
868
869 if( Fault )
870 return false;
871
872 // erase the previous outline data and vertex order
873 // but preserve the extra vertices
874 while( !outline.empty() )
875 {
876 delete outline.back();
877 outline.pop_back();
878 }
879
880 ordmap.clear();
881 ord = 0;
882
883 // go through the vertex lists and reset ephemeral parameters
884 for( unsigned int i = 0; i < vertices.size(); ++i )
885 {
886 vertices[i]->o = -1;
887 }
888
889 for( unsigned int i = 0; i < extra_verts.size(); ++i )
890 {
891 extra_verts[i]->o = -1;
892 }
893
894 // close the polygon; this creates the outline points
895 // and the point ordering list 'ordmap'
896 solid.clear();
897 gluTessEndPolygon( tess );
898
899 // repeat the last operation but request a tesselated surface
900 // rather than an outline; this creates the triangles list.
901 gluTessProperty( tess, GLU_TESS_BOUNDARY_ONLY, GL_FALSE );
902
903 gluTessBeginPolygon( tess, this );
904
905 if( !pushOutline( holes ) )
906 return false;
907
908 gluTessEndPolygon( tess );
909
910 if( Fault )
911 return false;
912
913 return true;
914}
915
916
918{
919 // traverse the outline list to push all used vertices
920 if( outline.size() < 1 )
921 {
922 error = "pushOutline() failed: no vertices to push";
923 return false;
924 }
925
926 std::list<std::list<int>*>::const_iterator obeg = outline.begin();
927 std::list<std::list<int>*>::const_iterator oend = outline.end();
928
929 int nc = 0; // number of contours pushed
930
931 int pi;
932 std::list<int>::const_iterator begin;
933 std::list<int>::const_iterator end;
934 GLdouble pt[3];
935 VERTEX_3D* vp;
936
937 while( obeg != oend )
938 {
939 if( (*obeg)->size() < 3 )
940 {
941 ++obeg;
942 continue;
943 }
944
945 gluTessBeginContour( tess );
946
947 begin = (*obeg)->begin();
948 end = (*obeg)->end();
949
950 while( begin != end )
951 {
952 pi = *begin;
953
954 if( pi < 0 || (unsigned int) pi > ordmap.size() )
955 {
956 gluTessEndContour( tess );
957 error = "pushOutline():BUG: *outline.begin() is not a valid index to ordmap";
958 return false;
959 }
960
961 // retrieve the actual index
962 pi = ordmap[pi];
963
964 vp = getVertexByIndex( pi, holes );
965
966 if( !vp )
967 {
968 gluTessEndContour( tess );
969 error = "pushOutline():: BUG: ordmap[n] is not a valid index to vertices[]";
970 return false;
971 }
972
973 pt[0] = vp->x;
974 pt[1] = vp->y;
975 pt[2] = 0.0;
976 gluTessVertex( tess, pt, vp );
977 ++begin;
978 }
979
980 gluTessEndContour( tess );
981 ++obeg;
982 ++nc;
983 }
984
985 if( !nc )
986 {
987 error = "pushOutline():: no valid contours available";
988 return false;
989 }
990
991 return true;
992}
993
994
995bool VRML_LAYER::WriteVertices( double aZcoord, std::ostream& aOutFile, int aPrecision )
996{
997 if( ordmap.size() < 3 )
998 {
999 error = "WriteVertices(): not enough vertices";
1000 return false;
1001 }
1002
1003 if( aPrecision < 4 )
1004 aPrecision = 4;
1005
1006 int i, j;
1007
1009
1010 if( !vp )
1011 return false;
1012
1013 std::string strx, stry, strz;
1014 FormatDoublet( vp->x + offsetX, vp->y + offsetY, aPrecision, strx, stry );
1015 FormatSinglet( aZcoord, aPrecision, strz );
1016
1017 aOutFile << strx << " " << stry << " " << strz;
1018
1019 for( i = 1, j = ordmap.size(); i < j; ++i )
1020 {
1021 vp = getVertexByIndex( ordmap[i], pholes );
1022
1023 if( !vp )
1024 return false;
1025
1026 FormatDoublet( vp->x + offsetX, vp->y + offsetY, aPrecision, strx, stry );
1027
1028 if( i & 1 )
1029 aOutFile << ", " << strx << " " << stry << " " << strz;
1030 else
1031 aOutFile << ",\n" << strx << " " << stry << " " << strz;
1032 }
1033
1034 return !aOutFile.fail();
1035}
1036
1037
1038bool VRML_LAYER::Write3DVertices( double aTopZ, double aBottomZ, std::ostream& aOutFile,
1039 int aPrecision )
1040{
1041 if( ordmap.size() < 3 )
1042 {
1043 error = "Write3DVertices(): insufficient vertices";
1044 return false;
1045 }
1046
1047 if( aPrecision < 4 )
1048 aPrecision = 4;
1049
1050 if( aTopZ <= aBottomZ )
1051 {
1052 error = "Write3DVertices(): top <= bottom";
1053 return false;
1054 }
1055
1056 int i, j;
1057
1059
1060 if( !vp )
1061 return false;
1062
1063 std::string strx, stry, strz;
1064 FormatDoublet( vp->x + offsetX, vp->y + offsetY, aPrecision, strx, stry );
1065 FormatSinglet( aTopZ, aPrecision, strz );
1066
1067 aOutFile << strx << " " << stry << " " << strz;
1068
1069 for( i = 1, j = ordmap.size(); i < j; ++i )
1070 {
1071 vp = getVertexByIndex( ordmap[i], pholes );
1072
1073 if( !vp )
1074 return false;
1075
1076 FormatDoublet( vp->x + offsetX, vp->y + offsetY, aPrecision, strx, stry );
1077
1078 if( i & 1 )
1079 aOutFile << ", " << strx << " " << stry << " " << strz;
1080 else
1081 aOutFile << ",\n" << strx << " " << stry << " " << strz;
1082 }
1083
1084 // repeat for the bottom layer
1085 vp = getVertexByIndex( ordmap[0], pholes );
1086 FormatDoublet( vp->x + offsetX, vp->y + offsetY, aPrecision, strx, stry );
1087 FormatSinglet( aBottomZ, aPrecision, strz );
1088
1089 bool endl;
1090
1091 if( i & 1 )
1092 {
1093 aOutFile << ", " << strx << " " << stry << " " << strz;
1094 endl = false;
1095 }
1096 else
1097 {
1098 aOutFile << ",\n" << strx << " " << stry << " " << strz;
1099 endl = true;
1100 }
1101
1102 for( i = 1, j = ordmap.size(); i < j; ++i )
1103 {
1104 vp = getVertexByIndex( ordmap[i], pholes );
1105 FormatDoublet( vp->x + offsetX, vp->y + offsetY, aPrecision, strx, stry );
1106
1107 if( endl )
1108 {
1109 aOutFile << ", " << strx << " " << stry << " " << strz;
1110 endl = false;
1111 }
1112 else
1113 {
1114 aOutFile << ",\n" << strx << " " << stry << " " << strz;
1115 endl = true;
1116 }
1117 }
1118
1119 return !aOutFile.fail();
1120}
1121
1122
1123bool VRML_LAYER::WriteIndices( bool aTopFlag, std::ostream& aOutFile )
1124{
1125 if( triplets.empty() )
1126 {
1127 error = "WriteIndices(): no triplets (triangular facets) to write";
1128 return false;
1129 }
1130
1131 // go through the triplet list and write out the indices based on order
1132 std::list<TRIPLET_3D>::const_iterator tbeg = triplets.begin();
1133 std::list<TRIPLET_3D>::const_iterator tend = triplets.end();
1134
1135 int i = 1;
1136
1137 if( aTopFlag )
1138 aOutFile << tbeg->i1 << ", " << tbeg->i2 << ", " << tbeg->i3 << ", -1";
1139 else
1140 aOutFile << tbeg->i2 << ", " << tbeg->i1 << ", " << tbeg->i3 << ", -1";
1141
1142 ++tbeg;
1143
1144 while( tbeg != tend )
1145 {
1146 if( (i++ & 7) == 4 )
1147 {
1148 i = 1;
1149
1150 if( aTopFlag )
1151 aOutFile << ",\n" << tbeg->i1 << ", " << tbeg->i2 << ", " << tbeg->i3 << ", -1";
1152 else
1153 aOutFile << ",\n" << tbeg->i2 << ", " << tbeg->i1 << ", " << tbeg->i3 << ", -1";
1154 }
1155 else
1156 {
1157 if( aTopFlag )
1158 aOutFile << ", " << tbeg->i1 << ", " << tbeg->i2 << ", " << tbeg->i3 << ", -1";
1159 else
1160 aOutFile << ", " << tbeg->i2 << ", " << tbeg->i1 << ", " << tbeg->i3 << ", -1";
1161 }
1162
1163 ++tbeg;
1164 }
1165
1166 return !aOutFile.fail();
1167}
1168
1169
1170bool VRML_LAYER::Write3DIndices( std::ostream& aOutFile, bool aIncludePlatedHoles )
1171{
1172 if( outline.empty() )
1173 {
1174 error = "WriteIndices(): no outline available";
1175 return false;
1176 }
1177
1178 char mark;
1179 bool holes_only = triplets.empty();
1180
1181 int i = 1;
1182 int idx2 = ordmap.size(); // index to the bottom vertices
1183
1184 if( !holes_only )
1185 {
1186 mark = ',';
1187
1188 // go through the triplet list and write out the indices based on order
1189 std::list<TRIPLET_3D>::const_iterator tbeg = triplets.begin();
1190 std::list<TRIPLET_3D>::const_iterator tend = triplets.end();
1191
1192 // print out the top vertices
1193 aOutFile << tbeg->i1 << ", " << tbeg->i2 << ", " << tbeg->i3 << ", -1";
1194 ++tbeg;
1195
1196 while( tbeg != tend )
1197 {
1198 if( (i++ & 7) == 4 )
1199 {
1200 i = 1;
1201 aOutFile << ",\n" << tbeg->i1 << ", " << tbeg->i2 << ", " << tbeg->i3 << ", -1";
1202 }
1203 else
1204 {
1205 aOutFile << ", " << tbeg->i1 << ", " << tbeg->i2 << ", " << tbeg->i3 << ", -1";
1206 }
1207
1208 ++tbeg;
1209 }
1210
1211 // print out the bottom vertices
1212 tbeg = triplets.begin();
1213
1214 while( tbeg != tend )
1215 {
1216 if( ( i++ & 7 ) == 4 )
1217 {
1218 i = 1;
1219 aOutFile << ",\n"
1220 << ( tbeg->i2 + idx2 ) << ", " << ( tbeg->i1 + idx2 ) << ", "
1221 << ( tbeg->i3 + idx2 ) << ", -1";
1222 }
1223 else
1224 {
1225 aOutFile << ", " << ( tbeg->i2 + idx2 ) << ", " << ( tbeg->i1 + idx2 ) << ", "
1226 << ( tbeg->i3 + idx2 ) << ", -1";
1227 }
1228
1229 ++tbeg;
1230 }
1231 }
1232 else
1233 mark = ' ';
1234
1235 // print out indices for the walls joining top to bottom
1236 int lastPoint;
1237 int curPoint;
1238 int curContour = 0;
1239
1240 std::list<std::list<int>*>::const_iterator obeg = outline.begin();
1241 std::list<std::list<int>*>::const_iterator oend = outline.end();
1242 std::list<int>* cp;
1243 std::list<int>::const_iterator cbeg;
1244 std::list<int>::const_iterator cend;
1245
1246 i = 2;
1247
1248 while( obeg != oend )
1249 {
1250 cp = *obeg;
1251
1252 if( cp->size() < 3 )
1253 {
1254 ++obeg;
1255 ++curContour;
1256 continue;
1257 }
1258
1259 cbeg = cp->begin();
1260 cend = cp->end();
1261 lastPoint = *(cbeg++);
1262
1263 // skip all PTH vertices which are not in a solid outline
1264 if( !aIncludePlatedHoles && !solid[curContour]
1265 && getVertexByIndex( ordmap[lastPoint], pholes )->pth )
1266 {
1267 ++obeg;
1268 ++curContour;
1269 continue;
1270 }
1271
1272 while( cbeg != cend )
1273 {
1274 curPoint = *(cbeg++);
1275
1276 if( !holes_only )
1277 {
1278 if( ( i++ & 3 ) == 2 )
1279 {
1280 i = 1;
1281 aOutFile << mark << "\n"
1282 << curPoint << ", " << lastPoint << ", " << curPoint + idx2;
1283 aOutFile << ", -1, " << curPoint + idx2 << ", " << lastPoint << ", "
1284 << lastPoint + idx2 << ", -1";
1285 }
1286 else
1287 {
1288 aOutFile << mark << " " << curPoint << ", " << lastPoint << ", "
1289 << curPoint + idx2;
1290 aOutFile << ", -1, " << curPoint + idx2 << ", " << lastPoint << ", "
1291 << lastPoint + idx2 << ", -1";
1292 }
1293 }
1294 else
1295 {
1296 if( (i++ & 3) == 2 )
1297 {
1298 i = 1;
1299 aOutFile << mark << "\n"
1300 << curPoint << ", " << curPoint + idx2 << ", " << lastPoint;
1301 aOutFile << ", -1, " << curPoint + idx2 << ", " << lastPoint + idx2 << ", "
1302 << lastPoint << ", -1";
1303 }
1304 else
1305 {
1306 aOutFile << mark << " " << curPoint << ", " << curPoint + idx2 << ", "
1307 << lastPoint;
1308 aOutFile << ", -1, " << curPoint + idx2 << ", " << lastPoint + idx2 << ", "
1309 << lastPoint << ", -1";
1310 }
1311 }
1312
1313 mark = ',';
1314 lastPoint = curPoint;
1315 }
1316
1317 // check if the loop needs to be closed
1318 cbeg = cp->begin();
1319 cend = --cp->end();
1320
1321 curPoint = *(cbeg);
1322 lastPoint = *(cend);
1323
1324 if( !holes_only )
1325 {
1326 if( ( i++ & 3 ) == 2 )
1327 {
1328 aOutFile << ",\n" << curPoint << ", " << lastPoint << ", " << curPoint + idx2;
1329 aOutFile << ", -1, " << curPoint + idx2 << ", " << lastPoint << ", "
1330 << lastPoint + idx2 << ", -1";
1331 }
1332 else
1333 {
1334 aOutFile << ", " << curPoint << ", " << lastPoint << ", " << curPoint + idx2;
1335 aOutFile << ", -1, " << curPoint + idx2 << ", " << lastPoint << ", "
1336 << lastPoint + idx2 << ", -1";
1337 }
1338 }
1339 else
1340 {
1341 if( ( i++ & 3 ) == 2 )
1342 {
1343 aOutFile << ",\n" << curPoint << ", " << curPoint + idx2 << ", " << lastPoint;
1344 aOutFile << ", -1, " << curPoint + idx2 << ", " << lastPoint + idx2 << ", "
1345 << lastPoint << ", -1";
1346 }
1347 else
1348 {
1349 aOutFile << ", " << curPoint << ", " << curPoint + idx2 << ", " << lastPoint;
1350 aOutFile << ", -1, " << curPoint + idx2 << ", " << lastPoint + idx2 << ", "
1351 << lastPoint << ", -1";
1352 }
1353 }
1354
1355 ++obeg;
1356 ++curContour;
1357 }
1358
1359 return !aOutFile.fail();
1360}
1361
1362
1364{
1365 double dx0 = p1->x - p0->x;
1366 double dx1 = p2->x - p0->x;
1367 double dx2 = p2->x - p1->x;
1368
1369 double dy0 = p1->y - p0->y;
1370 double dy1 = p2->y - p0->y;
1371 double dy2 = p2->y - p1->y;
1372
1373 dx0 *= dx0;
1374 dx1 *= dx1;
1375 dx2 *= dx2;
1376
1377 dy0 *= dy0;
1378 dy1 *= dy1;
1379 dy2 *= dy2;
1380
1381 // this number is chosen because we shall only write 9 decimal places
1382 // at most on the VRML output
1383 double err = 0.000000001;
1384
1385 // test if the triangles are degenerate (equal points)
1386 if( ( dx0 + dy0 ) < err )
1387 return false;
1388
1389 if( ( dx1 + dy1 ) < err )
1390 return false;
1391
1392 if( ( dx2 + dy2 ) < err )
1393 return false;
1394
1395 triplets.emplace_back( p0->o, p1->o, p2->o );
1396
1397 return true;
1398}
1399
1400
1401VERTEX_3D* VRML_LAYER::AddExtraVertex( double aXpos, double aYpos, bool aPlatedHole )
1402{
1403 VERTEX_3D* vertex = new VERTEX_3D;
1404
1405 if( eidx == 0 )
1406 eidx = idx + hidx;
1407
1408 vertex->x = aXpos;
1409 vertex->y = aYpos;
1410 vertex->i = eidx++;
1411 vertex->o = -1;
1412 vertex->pth = aPlatedHole;
1413
1414 extra_verts.push_back( vertex );
1415
1416 return vertex;
1417}
1418
1419
1421{
1422 glcmd = cmd;
1423
1424 while( !vlist.empty() )
1425 vlist.pop_back();
1426}
1427
1428
1430{
1431 if( vertex->o < 0 )
1432 {
1433 vertex->o = ord++;
1434 ordmap.push_back( vertex->i );
1435 }
1436
1437 vlist.push_back( vertex );
1438}
1439
1440
1442{
1443 switch( glcmd )
1444 {
1445 case GL_LINE_LOOP:
1446 {
1447 // add the loop to the list of outlines
1448 std::list<int>* loop = new std::list<int>;
1449
1450 double firstX = 0.0;
1451 double firstY = 0.0;
1452 double lastX = 0.0;
1453 double lastY = 0.0;
1454 double curX, curY;
1455 double area = 0.0;
1456
1457 if( vlist.size() > 0 )
1458 {
1459 loop->push_back( vlist[0]->o );
1460 firstX = vlist[0]->x;
1461 firstY = vlist[0]->y;
1462 lastX = firstX;
1463 lastY = firstY;
1464 }
1465
1466 for( size_t i = 1; i < vlist.size(); ++i )
1467 {
1468 loop->push_back( vlist[i]->o );
1469 curX = vlist[i]->x;
1470 curY = vlist[i]->y;
1471 area += ( curX - lastX ) * ( curY + lastY );
1472 lastX = curX;
1473 lastY = curY;
1474 }
1475
1476 area += ( firstX - lastX ) * ( firstY + lastY );
1477
1478 outline.push_back( loop );
1479
1480 if( area <= 0.0 )
1481 solid.push_back( true );
1482 else
1483 solid.push_back( false );
1484 }
1485
1486 break;
1487
1488 case GL_TRIANGLE_FAN:
1489 processFan();
1490 break;
1491
1492 case GL_TRIANGLE_STRIP:
1493 processStrip();
1494 break;
1495
1496 case GL_TRIANGLES:
1497 processTri();
1498 break;
1499
1500 default:
1501 break;
1502 }
1503
1504 while( !vlist.empty() )
1505 vlist.pop_back();
1506
1507 glcmd = 0;
1508}
1509
1510
1512{
1513 const char * msg = (const char*)gluErrorString( errorID );
1514
1515 // If errorID is an illegal id, gluErrorString returns NULL
1516 if( msg )
1517 error = msg;
1518 else
1519 error.clear();
1520
1521 if( error.empty() )
1522 {
1523 std::ostringstream ostr;
1524 ostr << "Unknown OpenGL error: " << errorID;
1525 error = ostr.str();
1526 }
1527}
1528
1529
1531{
1532 if( vlist.size() < 3 )
1533 return;
1534
1535 VERTEX_3D* p0 = vlist[0];
1536
1537 int i;
1538 int end = vlist.size();
1539
1540 for( i = 2; i < end; ++i )
1541 {
1542 addTriplet( p0, vlist[i - 1], vlist[i] );
1543 }
1544}
1545
1546
1548{
1549 // note: (source: http://www.opengl.org/wiki/Primitive)
1550 // GL_TRIANGLE_STRIP​: Every group of 3 adjacent vertices forms a triangle.
1551 // The face direction of the strip is determined by the winding of the
1552 // first triangle. Each successive triangle will have its effective face
1553 // order reverse, so the system compensates for that by testing it in the
1554 // opposite way. A vertex stream of n length will generate n-2 triangles.
1555
1556 if( vlist.size() < 3 )
1557 return;
1558
1559 int i;
1560 int end = vlist.size();
1561 bool flip = false;
1562
1563 for( i = 2; i < end; ++i )
1564 {
1565 if( flip )
1566 {
1567 addTriplet( vlist[i - 1], vlist[i - 2], vlist[i] );
1568 flip = false;
1569 }
1570 else
1571 {
1572 addTriplet( vlist[i - 2], vlist[i - 1], vlist[i] );
1573 flip = true;
1574 }
1575 }
1576}
1577
1578
1580{
1581 // notes:
1582 // 1. each successive group of 3 vertices is a triangle
1583 // 2. as per OpenGL specification, any incomplete triangles are to be ignored
1584
1585 if( vlist.size() < 3 )
1586 return;
1587
1588 int i;
1589 int end = vlist.size();
1590
1591 for( i = 2; i < end; i += 3 )
1592 addTriplet( vlist[i - 2], vlist[i - 1], vlist[i] );
1593}
1594
1595
1597{
1598 int nc = 0; // number of contours
1599
1600 if( contours.empty() )
1601 return 0;
1602
1603 for( size_t i = 0; i < contours.size(); ++i )
1604 {
1605 if( contours[i]->size() < 3 )
1606 continue;
1607
1608 if( ( holes && areas[i] <= 0.0 ) || ( !holes && areas[i] > 0.0 ) )
1609 continue;
1610
1611 ++nc;
1612 }
1613
1614 return nc;
1615}
1616
1617
1619{
1620 // push the internally held vertices
1621 unsigned int i;
1622
1623 std::list<int>::const_iterator begin;
1624 std::list<int>::const_iterator end;
1625 GLdouble pt[3];
1626 VERTEX_3D* vp;
1627
1628 for( i = 0; i < contours.size(); ++i )
1629 {
1630 if( contours[i]->size() < 3 )
1631 continue;
1632
1633 if( ( holes && areas[i] <= 0.0 ) || ( !holes && areas[i] > 0.0 ) )
1634 continue;
1635
1636 gluTessBeginContour( tess );
1637
1638 begin = contours[i]->begin();
1639 end = contours[i]->end();
1640
1641 while( begin != end )
1642 {
1643 vp = vertices[ *begin ];
1644 pt[0] = vp->x;
1645 pt[1] = vp->y;
1646 pt[2] = 0.0;
1647 gluTessVertex( tess, pt, vp );
1648 ++begin;
1649 }
1650
1651 gluTessEndContour( tess );
1652 }
1653
1654 return;
1655}
1656
1657
1659{
1660 if( aPointIndex < 0 || (unsigned int) aPointIndex >= ( idx + hidx + extra_verts.size() ) )
1661 {
1662 error = "getVertexByIndex():BUG: invalid index";
1663 return NULL;
1664 }
1665
1666 if( aPointIndex < idx )
1667 {
1668 // vertex is in the vertices[] list
1669 return vertices[ aPointIndex ];
1670 }
1671 else if( aPointIndex >= idx + hidx )
1672 {
1673 // vertex is in the extra_verts[] list
1674 return extra_verts[aPointIndex - idx - hidx];
1675 }
1676
1677 // vertex is in the holes object
1678 if( !holes )
1679 {
1680 error = "getVertexByIndex():BUG: invalid index";
1681 return NULL;
1682 }
1683
1684 VERTEX_3D* vp = holes->GetVertexByIndex( aPointIndex );
1685
1686 if( !vp )
1687 {
1688 std::ostringstream ostr;
1689 ostr << "getVertexByIndex():FAILED: " << holes->GetError();
1690 error = ostr.str();
1691 return NULL;
1692 }
1693
1694 return vp;
1695}
1696
1697
1699{
1700 return vertices.size();
1701}
1702
1703
1704int VRML_LAYER::Import( int start, GLUtesselator* aTesselator )
1705{
1706 if( start < 0 )
1707 {
1708 error = "Import(): invalid index ( start < 0 )";
1709 return -1;
1710 }
1711
1712 if( !aTesselator )
1713 {
1714 error = "Import(): NULL tesselator pointer";
1715 return -1;
1716 }
1717
1718 unsigned int i, j;
1719
1720 // renumber from 'start'
1721 for( i = 0, j = vertices.size(); i < j; ++i )
1722 {
1723 vertices[i]->i = start++;
1724 vertices[i]->o = -1;
1725 }
1726
1727 // push each contour to the tesselator
1728 VERTEX_3D* vp;
1729 GLdouble pt[3];
1730
1731 std::list<int>::const_iterator cbeg;
1732 std::list<int>::const_iterator cend;
1733
1734 for( i = 0; i < contours.size(); ++i )
1735 {
1736 if( contours[i]->size() < 3 )
1737 continue;
1738
1739 cbeg = contours[i]->begin();
1740 cend = contours[i]->end();
1741
1742 gluTessBeginContour( aTesselator );
1743
1744 while( cbeg != cend )
1745 {
1746 vp = vertices[ *cbeg++ ];
1747 pt[0] = vp->x;
1748 pt[1] = vp->y;
1749 pt[2] = 0.0;
1750 gluTessVertex( aTesselator, pt, vp );
1751 }
1752
1753 gluTessEndContour( aTesselator );
1754 }
1755
1756 return start;
1757}
1758
1759
1761{
1762 int i0 = vertices[0]->i;
1763
1764 if( aPointIndex < i0 || aPointIndex >= ( i0 + (int) vertices.size() ) )
1765 {
1766 error = "GetVertexByIndex(): invalid index";
1767 return NULL;
1768 }
1769
1770 return vertices[aPointIndex - i0];
1771}
1772
1773
1774const std::string& VRML_LAYER::GetError( void )
1775{
1776 return error;
1777}
1778
1779
1780void VRML_LAYER::SetVertexOffsets( double aXoffset, double aYoffset )
1781{
1782 offsetX = aXoffset;
1783 offsetY = aYoffset;
1784 return;
1785}
1786
1787
1788bool VRML_LAYER::Get3DTriangles( std::vector< double >& aVertexList,
1789 std::vector< int > &aIndexPlane, std::vector< int > &aIndexSide,
1790 double aTopZ, double aBotZ )
1791{
1792 aVertexList.clear();
1793 aIndexPlane.clear();
1794 aIndexSide.clear();
1795
1796 if( ordmap.size() < 3 || outline.empty() )
1797 return false;
1798
1799 if( aTopZ <= aBotZ )
1800 {
1801 double tmp = aBotZ;
1802 aBotZ = aTopZ;
1803 aTopZ = tmp;
1804 }
1805
1807
1808 if( !vp )
1809 return false;
1810
1811 size_t i;
1812 size_t vsize = ordmap.size();
1813
1814 // top vertices
1815 for( i = 0; i < vsize; ++i )
1816 {
1817 vp = getVertexByIndex( ordmap[i], pholes );
1818
1819 if( !vp )
1820 {
1821 aVertexList.clear();
1822 return false;
1823 }
1824
1825 aVertexList.push_back( vp->x + offsetX );
1826 aVertexList.push_back( vp->y + offsetY );
1827 aVertexList.push_back( aTopZ );
1828 }
1829
1830 // bottom vertices
1831 for( i = 0; i < vsize; ++i )
1832 {
1833 vp = getVertexByIndex( ordmap[i], pholes );
1834
1835 aVertexList.push_back( vp->x + offsetX );
1836 aVertexList.push_back( vp->y + offsetY );
1837 aVertexList.push_back( aBotZ );
1838 }
1839
1840 // create the index lists .. it is difficult to estimate the list size
1841 // a priori so instead we use a vector to help
1842
1843 bool holes_only = triplets.empty();
1844
1845 if( !holes_only )
1846 {
1847 // go through the triplet list and write out the indices based on order
1848 std::list< TRIPLET_3D >::const_iterator tbeg = triplets.begin();
1849 std::list< TRIPLET_3D >::const_iterator tend = triplets.end();
1850
1851 std::vector< int > aIndexBot;
1852
1853 while( tbeg != tend )
1854 {
1855 // top vertices
1856 aIndexPlane.push_back( (int) tbeg->i1 );
1857 aIndexPlane.push_back( (int) tbeg->i2 );
1858 aIndexPlane.push_back( (int) tbeg->i3 );
1859
1860 // bottom vertices
1861 aIndexBot.push_back( (int) ( tbeg->i2 + vsize ) );
1862 aIndexBot.push_back( (int) ( tbeg->i1 + vsize ) );
1863 aIndexBot.push_back( (int) ( tbeg->i3 + vsize ) );
1864
1865 ++tbeg;
1866 }
1867
1868 aIndexPlane.insert( aIndexPlane.end(), aIndexBot.begin(), aIndexBot.end() );
1869 }
1870
1871 // compile indices for the walls joining top to bottom
1872 int lastPoint;
1873 int curPoint;
1874
1875 std::list< std::list< int >* >::const_iterator obeg = outline.begin();
1876 std::list< std::list< int >* >::const_iterator oend = outline.end();
1877 std::list< int >* cp;
1878 std::list< int >::const_iterator cbeg;
1879 std::list< int >::const_iterator cend;
1880
1881 i = 2;
1882
1883 while( obeg != oend )
1884 {
1885 cp = *obeg;
1886
1887 if( cp->size() < 3 )
1888 {
1889 ++obeg;
1890 continue;
1891 }
1892
1893 cbeg = cp->begin();
1894 cend = cp->end();
1895 lastPoint = *(cbeg++);
1896
1897 while( cbeg != cend )
1898 {
1899 curPoint = *(cbeg++);
1900
1901 if( !holes_only )
1902 {
1903 aIndexSide.push_back( curPoint );
1904 aIndexSide.push_back( lastPoint );
1905 aIndexSide.push_back( (int)( curPoint + vsize ) );
1906
1907 aIndexSide.push_back( (int)( curPoint + vsize ) );
1908 aIndexSide.push_back( lastPoint );
1909 aIndexSide.push_back( (int)( lastPoint + vsize ) );
1910 }
1911 else
1912 {
1913 aIndexSide.push_back( curPoint );
1914 aIndexSide.push_back( (int)( curPoint + vsize ) );
1915 aIndexSide.push_back( lastPoint );
1916
1917 aIndexSide.push_back( (int)( curPoint + vsize ) );
1918 aIndexSide.push_back( (int)( lastPoint + vsize ) );
1919 aIndexSide.push_back( lastPoint );
1920 }
1921
1922 lastPoint = curPoint;
1923 }
1924
1925 // check if the loop needs to be closed
1926 cbeg = cp->begin();
1927 cend = --cp->end();
1928
1929 curPoint = *(cbeg);
1930 lastPoint = *(cend);
1931
1932 if( !holes_only )
1933 {
1934 aIndexSide.push_back( curPoint );
1935 aIndexSide.push_back( lastPoint );
1936 aIndexSide.push_back( (int)( curPoint + vsize ) );
1937
1938 aIndexSide.push_back( (int)( curPoint + vsize ) );
1939 aIndexSide.push_back( lastPoint );
1940 aIndexSide.push_back( (int)( lastPoint + vsize ) );
1941 }
1942 else
1943 {
1944 aIndexSide.push_back( curPoint );
1945 aIndexSide.push_back( (int)( curPoint + vsize ) );
1946 aIndexSide.push_back( lastPoint );
1947
1948 aIndexSide.push_back( (int)( curPoint + vsize ) );
1949 aIndexSide.push_back( (int)( lastPoint + vsize ) );
1950 aIndexSide.push_back( lastPoint );
1951 }
1952
1953 ++obeg;
1954 }
1955
1956 return true;
1957}
1958
1959
1960bool VRML_LAYER::Get2DTriangles( std::vector< double >& aVertexList,
1961 std::vector< int > &aIndexPlane, double aHeight, bool aTopPlane )
1962{
1963 aVertexList.clear();
1964 aIndexPlane.clear();
1965
1966 if( ordmap.size() < 3 || outline.empty() )
1967 return false;
1968
1970
1971 if( !vp )
1972 return false;
1973
1974 size_t i;
1975 size_t vsize = ordmap.size();
1976
1977 // vertices
1978 for( i = 0; i < vsize; ++i )
1979 {
1980 vp = getVertexByIndex( ordmap[i], pholes );
1981
1982 if( !vp )
1983 {
1984 aVertexList.clear();
1985 return false;
1986 }
1987
1988 aVertexList.push_back( vp->x + offsetX );
1989 aVertexList.push_back( vp->y + offsetY );
1990 aVertexList.push_back( aHeight );
1991 }
1992
1993 // create the index lists .. it is difficult to estimate the list size
1994 // a priori so instead we use a vector to help
1995
1996 if( triplets.empty() )
1997 return false;
1998
1999 // go through the triplet list and write out the indices based on order
2000 std::list< TRIPLET_3D >::const_iterator tbeg = triplets.begin();
2001 std::list< TRIPLET_3D >::const_iterator tend = triplets.end();
2002
2003 if( aTopPlane )
2004 {
2005 while( tbeg != tend )
2006 {
2007 // top vertices
2008 aIndexPlane.push_back( (int) tbeg->i1 );
2009 aIndexPlane.push_back( (int) tbeg->i2 );
2010 aIndexPlane.push_back( (int) tbeg->i3 );
2011
2012 ++tbeg;
2013 }
2014 }
2015 else
2016 {
2017 while( tbeg != tend )
2018 {
2019 // bottom vertices
2020 aIndexPlane.push_back( (int) ( tbeg->i2 ) );
2021 aIndexPlane.push_back( (int) ( tbeg->i1 ) );
2022 aIndexPlane.push_back( (int) ( tbeg->i3 ) );
2023
2024 ++tbeg;
2025 }
2026 }
2027
2028 return true;
2029}
void GetArcParams(int &aMaxSeg, double &aMinLength, double &aMaxLength)
Retrieve the parameters used in calculating the number of vertices in an arc.
virtual ~VRML_LAYER()
std::vector< double > areas
Definition vrml_layer.h:422
bool AddSlot(double aCenterX, double aCenterY, double aSlotLength, double aSlotWidth, double aAngle, bool aHoleFlag=false, bool aPlatedHole=false)
Create and add a slot feature to the list of contours.
bool AddPolygon(const std::vector< wxRealPoint > &aPolySet, double aCenterX, double aCenterY, double aAngle)
Create an arbitrary polygon and adds it to the list of contours.
int Import(int start, GLUtesselator *aTesselator)
Inserts all contours into the given tesselator.
bool WriteIndices(bool aTopFlag, std::ostream &aOutFile)
Write out the vertex sets required to render a planar surface.
void ResetArcParams()
Reset the parameters used in calculating the number of vertices in an arc to default values.
std::vector< bool > solid
Definition vrml_layer.h:421
std::vector< std::list< int > * > contours
Definition vrml_layer.h:419
bool Tesselate(VRML_LAYER *holes=NULL, bool aHolesOnly=false)
Create a list of outline vertices as well as the vertex sets required to render the surface.
void glStart(GLenum cmd)
Invoked by the GLU tesselator callback to notify this object of the type of GL command which is appli...
double maxSegLength
Definition vrml_layer.h:409
bool SetArcParams(int aMaxSeg, double aMinLength, double aMaxLength)
Set the parameters used in calculating the number of vertices in an arc.
std::vector< VERTEX_3D * > extra_verts
Definition vrml_layer.h:431
std::vector< bool > pth
Definition vrml_layer.h:420
bool Fault
set to true when a fault is encountered during tesselation
Definition vrml_layer.h:403
void SetVertexOffsets(double aXoffset, double aYoffset)
bool Get3DTriangles(std::vector< double > &aVertexList, std::vector< int > &aIndexPlane, std::vector< int > &aIndexSide, double aTopZ, double aBotZ)
Allocate and populate the 3D vertex and index lists with triangular vertices which may be used for re...
bool Write3DIndices(std::ostream &aOutFile, bool aIncludePlatedHoles=false)
Write out the vertex sets required to render an extruded solid.
bool WriteVertices(double aZcoord, std::ostream &aOutFile, int aPrecision)
Write out the list of vertices required to render a planar surface.
bool EnsureWinding(int aContourID, bool aHoleFlag)
Check the winding of a contour and ensures that it is a hole or a solid depending on the value of.
double offsetX
Definition vrml_layer.h:412
void clearTmp(void)
bool addTriplet(VERTEX_3D *p0, VERTEX_3D *p1, VERTEX_3D *p2)
bool AddCircle(double aXpos, double aYpos, double aRadius, bool aHoleFlag=false, bool aPlatedHole=false)
Create a circular contour and adds it to the internal list.
bool AddArc(double aCenterX, double aCenterY, double aStartX, double aStartY, double aArcWidth, double aAngle, bool aHoleFlag=false, bool aPlatedHole=false)
Create a slotted arc and adds it to the internal list of contours.
int GetSize(void)
double offsetY
Definition vrml_layer.h:413
void SetGLError(GLenum error_id)
Set the error message according to the specified OpenGL error.
bool Get2DTriangles(std::vector< double > &aVertexList, std::vector< int > &aIndexPlane, double aHeight, bool aTopPlane)
Allocate and populate the 3D vertex and index lists with triangular vertices which may be used for re...
bool AppendCircle(double aXpos, double aYpos, double aRadius, int aContourID, bool aHoleFlag=false)
Add a circular contour to the specified (empty) contour.
std::string error
Definition vrml_layer.h:427
bool pushOutline(VRML_LAYER *holes)
bool Write3DVertices(double aTopZ, double aBottomZ, std::ostream &aOutFile, int aPrecision)
Write out the list of vertices required to render an extruded solid.
VERTEX_3D * getVertexByIndex(int aPointIndex, VRML_LAYER *holes)
VRML_LAYER * pholes
Definition vrml_layer.h:433
void processStrip(void)
double minSegLength
Definition vrml_layer.h:408
int checkNContours(bool holes)
void glEnd(void)
Invoked by the GLU tesselator callback to notify this object that the vertex list is complete and rea...
std::vector< int > ordmap
Definition vrml_layer.h:425
void processFan(void)
void processTri(void)
std::list< TRIPLET_3D > triplets
Definition vrml_layer.h:423
int NewContour(bool aPlatedHole=false)
Create a new list of vertices and returns an index to the list.
VERTEX_3D * AddExtraVertex(double aXpos, double aYpos, bool aPlatedHole)
Add an extra vertex as required by the GLU tesselator.
std::vector< VERTEX_3D * > vertices
Definition vrml_layer.h:418
std::list< std::list< int > * > outline
Definition vrml_layer.h:424
const std::string & GetError(void)
int calcNSides(double aRadius, double aAngle)
void glPushVertex(VERTEX_3D *vertex)
Invoked by the GLU tesselator callback; the supplied vertex is added to the internal list of vertices...
std::vector< VERTEX_3D * > vlist
Definition vrml_layer.h:432
GLUtesselator * tess
Definition vrml_layer.h:436
GLenum glcmd
Definition vrml_layer.h:437
bool AppendArc(double aCenterX, double aCenterY, double aRadius, double aStartAngle, double aAngle, int aContourID)
Add an arc to the specified contour.
void Clear(void)
Erase all data except for arc parameters.
void pushVertices(bool holes)
bool AddVertex(int aContourID, double aXpos, double aYpos)
Add a point to the requested contour.
VERTEX_3D * GetVertexByIndex(int aPointIndex)
Return a pointer to the requested vertex or NULL if no such vertex exists.
@ DEGREES_T
Definition eda_angle.h:30
double x
Definition vrml_layer.h:56
double y
Definition vrml_layer.h:57
VECTOR2I end
VECTOR2I v2(1, 0)
#define M_PI
void RotatePoint(int *pX, int *pY, const EDA_ANGLE &aAngle)
Calculate the new point of coord coord pX, pY, for a rotation center 0, 0.
Definition trigo.cpp:227
static void CALLBACK vrml_tess_vertex(void *vertex_data, void *user_data)
static void CALLBACK vrml_tess_end(void *user_data)
static void CALLBACK vrml_tess_err(GLenum errorID, void *user_data)
static void FormatDoublet(double x, double y, int precision, std::string &strx, std::string &stry)
#define MIN_NSIDES
static void CALLBACK vrml_tess_begin(GLenum cmd, void *user_data)
static void CALLBACK vrml_tess_combine(GLdouble coords[3], VERTEX_3D *vertex_data[4], GLfloat weight[4], void **outData, void *user_data)
static void FormatSinglet(double x, int precision, std::string &strx)
#define GLCALLBACK(x)
#define CALLBACK
unsigned int GLenum
Definition vrml_layer.h:43
#define M_PI2
Definition vrml_layer.h:46