KiCad PCB EDA Suite
export_vrml.cpp
Go to the documentation of this file.
1 /*
2  * This program source code file is part of KiCad, a free EDA CAD application.
3  *
4  * Copyright (C) 2009-2013 Lorenzo Mercantonio
5  * Copyright (C) 2014-2017 Cirilo Bernardo
6  * Copyright (C) 2013 Jean-Pierre Charras jp.charras at wanadoo.fr
7  * Copyright (C) 2004-2016 KiCad Developers, see AUTHORS.txt for contributors.
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, you may find one here:
21  * http://www.gnu.org/licenses/old-licenses/gpl-2.0.html
22  * or you may search the http://www.gnu.org website for the version 2 license,
23  * or you may write to the Free Software Foundation, Inc.,
24  * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA
25  */
26 
27 #include <cmath>
28 #include <exception>
29 #include <fstream>
30 #include <iomanip>
31 #include <vector>
32 #include <wx/dir.h>
33 
34 #include "3d_cache/3d_cache.h"
35 #include "3d_cache/3d_info.h"
36 #include "class_board.h"
37 #include "class_edge_mod.h"
38 #include "class_module.h"
39 #include "class_pcb_text.h"
40 #include "class_track.h"
41 #include "class_zone.h"
42 #include "convert_to_biu.h"
43 #include "drawtxt.h"
44 #include "macros.h"
45 #include "pgm_base.h"
46 #include "plugins/3dapi/ifsg_all.h"
47 #include "streamwrapper.h"
48 #include "vrml_layer.h"
49 #include "wxPcbStruct.h"
50 #include "../../kicad/kicad.h"
51 
52 // minimum width (mm) of a VRML line
53 #define MIN_VRML_LINEWIDTH 0.12
54 
55 // offset for art layers, mm (silk, paste, etc)
56 #define ART_OFFSET 0.025
57 // offset for plating
58 #define PLATE_OFFSET 0.005
59 
60 static S3D_CACHE* cache;
61 static bool USE_INLINES; // true to use legacy inline{} behavior
62 static bool USE_DEFS; // true to reuse component definitions
63 static bool USE_RELPATH; // true to use relative paths in VRML inline{}
64 static double WORLD_SCALE = 1.0; // scaling from 0.1 in to desired VRML unit
65 static double BOARD_SCALE; // scaling from mm to desired VRML world scale
66 static const int PRECISION = 6; // legacy precision factor (now set to 6)
67 static wxString SUBDIR_3D; // legacy 3D subdirectory
68 static wxString PROJ_DIR; // project directory
69 
70 struct VRML_COLOR
71 {
72  float diffuse_red;
73  float diffuse_grn;
74  float diffuse_blu;
75 
76  float spec_red;
77  float spec_grn;
78  float spec_blu;
79 
80  float emit_red;
81  float emit_grn;
82  float emit_blu;
83 
84  float ambient;
85  float transp;
86  float shiny;
87 
89  {
90  // default green
91  diffuse_red = 0.13;
92  diffuse_grn = 0.81;
93  diffuse_blu = 0.22;
94  spec_red = 0.01;
95  spec_grn = 0.08;
96  spec_blu = 0.02;
97  emit_red = 0.0;
98  emit_grn = 0.0;
99  emit_blu = 0.0;
100 
101  ambient = 0.8;
102  transp = 0;
103  shiny = 0.02;
104  }
105 
106  VRML_COLOR( float dr, float dg, float db,
107  float sr, float sg, float sb,
108  float er, float eg, float eb,
109  float am, float tr, float sh )
110  {
111  diffuse_red = dr;
112  diffuse_grn = dg;
113  diffuse_blu = db;
114  spec_red = sr;
115  spec_grn = sg;
116  spec_blu = sb;
117  emit_red = er;
118  emit_grn = eg;
119  emit_blu = eb;
120 
121  ambient = am;
122  transp = tr;
123  shiny = sh;
124  }
125 };
126 
128 {
135 };
136 
138 static SGNODE* sgmaterial[VRML_COLOR_LAST] = { NULL };
139 
141 {
142 private:
144 
145  int m_iMaxSeg; // max. sides to a small circle
146  double m_arcMinLen, m_arcMaxLen; // min and max lengths of an arc chord
147 
148 public:
150  VRML_LAYER m_holes;
151  VRML_LAYER m_board;
152  VRML_LAYER m_top_copper;
153  VRML_LAYER m_bot_copper;
154  VRML_LAYER m_top_silk;
155  VRML_LAYER m_bot_silk;
156  VRML_LAYER m_top_tin;
157  VRML_LAYER m_bot_tin;
158  VRML_LAYER m_plated_holes;
159 
160  std::list< SGNODE* > m_components;
161 
163 
164  double m_minLineWidth; // minimum width of a VRML line segment
165 
166  double m_tx; // global translation along X
167  double m_ty; // global translation along Y
168 
169  double m_brd_thickness; // depth of the PCB
170 
173 
174  MODEL_VRML() : m_OutputPCB( (SGNODE*) NULL )
175  {
176  for( unsigned i = 0; i < DIM( m_layer_z ); ++i )
177  m_layer_z[i] = 0;
178 
179  m_holes.GetArcParams( m_iMaxSeg, m_arcMinLen, m_arcMaxLen );
180 
181  // this default only makes sense if the output is in mm
182  m_brd_thickness = 1.6;
183 
184  // pcb green
185  colors[ VRML_COLOR_PCB ] = VRML_COLOR( .07, .3, .12, .01, .03, .01,
186  0, 0, 0, 0.8, 0, 0.02 );
187  // track green
188  colors[ VRML_COLOR_TRACK ] = VRML_COLOR( .08, .5, .1, .01, .05, .01,
189  0, 0, 0, 0.8, 0, 0.02 );
190  // silkscreen white
191  colors[ VRML_COLOR_SILK ] = VRML_COLOR( .9, .9, .9, .1, .1, .1,
192  0, 0, 0, 0.9, 0, 0.02 );
193  // pad silver
194  colors[ VRML_COLOR_TIN ] = VRML_COLOR( .749, .756, .761, .749, .756, .761,
195  0, 0, 0, 0.8, 0, 0.8 );
196 
197  m_plainPCB = false;
198  SetOffset( 0.0, 0.0 );
199  m_text_layer = F_Cu;
200  m_text_width = 1;
201  m_minLineWidth = MIN_VRML_LINEWIDTH;
202  }
203 
205  {
206  // destroy any unassociated material appearances
207  for( int j = 0; j < VRML_COLOR_LAST; ++j )
208  {
209  if( sgmaterial[j] && NULL == S3D::GetSGNodeParent( sgmaterial[j] ) )
210  S3D::DestroyNode( sgmaterial[j] );
211 
212  sgmaterial[j] = NULL;
213  }
214 
215  if( !m_components.empty() )
216  {
217  IFSG_TRANSFORM tmp( false );
218 
219  for( auto i : m_components )
220  {
221  tmp.Attach( i );
222  tmp.SetParent( NULL );
223  }
224 
225  m_components.clear();
226  m_OutputPCB.Destroy();
227  }
228  }
229 
231  {
232  return colors[aIndex];
233  }
234 
235  void SetOffset( double aXoff, double aYoff )
236  {
237  m_tx = aXoff;
238  m_ty = -aYoff;
239 
240  m_holes.SetVertexOffsets( aXoff, aYoff );
241  m_board.SetVertexOffsets( aXoff, aYoff );
242  m_top_copper.SetVertexOffsets( aXoff, aYoff );
243  m_bot_copper.SetVertexOffsets( aXoff, aYoff );
244  m_top_silk.SetVertexOffsets( aXoff, aYoff );
245  m_bot_silk.SetVertexOffsets( aXoff, aYoff );
246  m_top_tin.SetVertexOffsets( aXoff, aYoff );
247  m_bot_tin.SetVertexOffsets( aXoff, aYoff );
248  m_plated_holes.SetVertexOffsets( aXoff, aYoff );
249  }
250 
251  double GetLayerZ( LAYER_NUM aLayer )
252  {
253  if( unsigned( aLayer ) >= DIM( m_layer_z ) )
254  return 0;
255 
256  return m_layer_z[ aLayer ];
257  }
258 
259  void SetLayerZ( LAYER_NUM aLayer, double aValue )
260  {
261  m_layer_z[aLayer] = aValue;
262  }
263 
264  // set the scaling of the VRML world
265  bool SetScale( double aWorldScale )
266  {
267  if( aWorldScale < 0.001 || aWorldScale > 10.0 )
268  throw( std::runtime_error( "WorldScale out of range (valid range is 0.001 to 10.0)" ) );
269 
270  m_OutputPCB.SetScale( aWorldScale * 2.54 );
271  WORLD_SCALE = aWorldScale * 2.54;
272 
273  return true;
274  }
275 
276 };
277 
278 
279 // static var. for dealing with text
281 
282 
283 // select the VRML layer object to draw on; return true if
284 // a layer has been selected.
285 static bool GetLayer( MODEL_VRML& aModel, LAYER_NUM layer, VRML_LAYER** vlayer )
286 {
287  switch( layer )
288  {
289  case B_Cu:
290  *vlayer = &aModel.m_bot_copper;
291  break;
292 
293  case F_Cu:
294  *vlayer = &aModel.m_top_copper;
295  break;
296 
297  case B_SilkS:
298  *vlayer = &aModel.m_bot_silk;
299  break;
300 
301  case F_SilkS:
302  *vlayer = &aModel.m_top_silk;
303  break;
304 
305  default:
306  return false;
307  }
308 
309  return true;
310 }
311 
312 static void create_vrml_shell( IFSG_TRANSFORM& PcbOutput, VRML_COLOR_INDEX colorID,
313  VRML_LAYER* layer, double top_z, double bottom_z );
314 
315 static void create_vrml_plane( IFSG_TRANSFORM& PcbOutput, VRML_COLOR_INDEX colorID,
316  VRML_LAYER* layer, double aHeight, bool aTopPlane );
317 
318 static void write_triangle_bag( std::ostream& aOut_file, VRML_COLOR& aColor,
319  VRML_LAYER* aLayer, bool aPlane, bool aTop,
320  double aTop_z, double aBottom_z )
321 {
322  /* A lot of nodes are not required, but blender sometimes chokes
323  * without them */
324  static const char* shape_boiler[] =
325  {
326  "Transform {\n",
327  " children [\n",
328  " Group {\n",
329  " children [\n",
330  " Shape {\n",
331  " appearance Appearance {\n",
332  " material Material {\n",
333  0, // Material marker
334  " }\n",
335  " }\n",
336  " geometry IndexedFaceSet {\n",
337  " solid TRUE\n",
338  " coord Coordinate {\n",
339  " point [\n",
340  0, // Coordinates marker
341  " ]\n",
342  " }\n",
343  " coordIndex [\n",
344  0, // Index marker
345  " ]\n",
346  " }\n",
347  " }\n",
348  " ]\n",
349  " }\n",
350  " ]\n",
351  "}\n",
352  0 // End marker
353  };
354 
355  int marker_found = 0, lineno = 0;
356 
357  while( marker_found < 4 )
358  {
359  if( shape_boiler[lineno] )
360  aOut_file << shape_boiler[lineno];
361  else
362  {
363  marker_found++;
364 
365  switch( marker_found )
366  {
367  case 1: // Material marker
368  aOut_file << " diffuseColor " << std::setprecision(3);
369  aOut_file << aColor.diffuse_red << " ";
370  aOut_file << aColor.diffuse_grn << " ";
371  aOut_file << aColor.diffuse_blu << "\n";
372 
373  aOut_file << " specularColor ";
374  aOut_file << aColor.spec_red << " ";
375  aOut_file << aColor.spec_grn << " ";
376  aOut_file << aColor.spec_blu << "\n";
377 
378  aOut_file << " emissiveColor ";
379  aOut_file << aColor.emit_red << " ";
380  aOut_file << aColor.emit_grn << " ";
381  aOut_file << aColor.emit_blu << "\n";
382 
383  aOut_file << " ambientIntensity " << aColor.ambient << "\n";
384  aOut_file << " transparency " << aColor.transp << "\n";
385  aOut_file << " shininess " << aColor.shiny << "\n";
386  break;
387 
388  case 2:
389 
390  if( aPlane )
391  aLayer->WriteVertices( aTop_z, aOut_file, PRECISION );
392  else
393  aLayer->Write3DVertices( aTop_z, aBottom_z, aOut_file, PRECISION );
394 
395  aOut_file << "\n";
396  break;
397 
398  case 3:
399 
400  if( aPlane )
401  aLayer->WriteIndices( aTop, aOut_file );
402  else
403  aLayer->Write3DIndices( aOut_file );
404 
405  aOut_file << "\n";
406  break;
407 
408  default:
409  break;
410  }
411  }
412 
413  lineno++;
414  }
415 }
416 
417 
418 static void write_layers( MODEL_VRML& aModel, BOARD* aPcb,
419  const char* aFileName, OSTREAM* aOutputFile )
420 {
421  // VRML_LAYER board;
422  aModel.m_board.Tesselate( &aModel.m_holes );
423  double brdz = aModel.m_brd_thickness / 2.0
424  - ( Millimeter2iu( ART_OFFSET / 2.0 ) ) * BOARD_SCALE;
425 
426  if( USE_INLINES )
427  {
428  write_triangle_bag( *aOutputFile, aModel.GetColor( VRML_COLOR_PCB ),
429  &aModel.m_board, false, false, brdz, -brdz );
430  }
431  else
432  {
433  create_vrml_shell( aModel.m_OutputPCB, VRML_COLOR_PCB, &aModel.m_board, brdz, -brdz );
434  }
435 
436  if( aModel.m_plainPCB )
437  {
438  if( !USE_INLINES )
439  S3D::WriteVRML( aFileName, true, aModel.m_OutputPCB.GetRawPtr(), USE_DEFS, true );
440 
441  return;
442  }
443 
444  // VRML_LAYER m_top_copper;
445  aModel.m_top_copper.Tesselate( &aModel.m_holes );
446 
447  if( USE_INLINES )
448  {
449  write_triangle_bag( *aOutputFile, aModel.GetColor( VRML_COLOR_TRACK ),
450  &aModel.m_top_copper, true, true,
451  aModel.GetLayerZ( F_Cu ), 0 );
452  }
453  else
454  {
456  aModel.GetLayerZ( F_Cu ), true );
457  }
458 
459  // VRML_LAYER m_top_tin;
460  aModel.m_top_tin.Tesselate( &aModel.m_holes );
461 
462  if( USE_INLINES )
463  {
464  write_triangle_bag( *aOutputFile, aModel.GetColor( VRML_COLOR_TIN ),
465  &aModel.m_top_tin, true, true,
466  aModel.GetLayerZ( F_Cu ) + Millimeter2iu( ART_OFFSET / 2.0 ) * BOARD_SCALE,
467  0 );
468  }
469  else
470  {
472  aModel.GetLayerZ( F_Cu ) + Millimeter2iu( ART_OFFSET / 2.0 ) * BOARD_SCALE,
473  true );
474  }
475 
476  // VRML_LAYER m_bot_copper;
477  aModel.m_bot_copper.Tesselate( &aModel.m_holes );
478 
479  if( USE_INLINES )
480  {
481  write_triangle_bag( *aOutputFile, aModel.GetColor( VRML_COLOR_TRACK ),
482  &aModel.m_bot_copper, true, false,
483  aModel.GetLayerZ( B_Cu ), 0 );
484  }
485  else
486  {
488  aModel.GetLayerZ( B_Cu ), false );
489  }
490 
491  // VRML_LAYER m_bot_tin;
492  aModel.m_bot_tin.Tesselate( &aModel.m_holes );
493 
494  if( USE_INLINES )
495  {
496  write_triangle_bag( *aOutputFile, aModel.GetColor( VRML_COLOR_TIN ),
497  &aModel.m_bot_tin, true, false,
498  aModel.GetLayerZ( B_Cu )
499  - Millimeter2iu( ART_OFFSET / 2.0 ) * BOARD_SCALE,
500  0 );
501  }
502  else
503  {
505  aModel.GetLayerZ( B_Cu ) - Millimeter2iu( ART_OFFSET / 2.0 ) * BOARD_SCALE,
506  false );
507  }
508 
509  // VRML_LAYER PTH;
510  aModel.m_plated_holes.Tesselate( NULL, true );
511 
512  if( USE_INLINES )
513  {
514  write_triangle_bag( *aOutputFile, aModel.GetColor( VRML_COLOR_TIN ),
515  &aModel.m_plated_holes, false, false,
516  aModel.GetLayerZ( F_Cu ) + Millimeter2iu( ART_OFFSET / 2.0 ) * BOARD_SCALE,
517  aModel.GetLayerZ( B_Cu ) - Millimeter2iu( ART_OFFSET / 2.0 ) * BOARD_SCALE );
518  }
519  else
520  {
522  aModel.GetLayerZ( F_Cu ) + Millimeter2iu( ART_OFFSET / 2.0 ) * BOARD_SCALE,
523  aModel.GetLayerZ( B_Cu ) - Millimeter2iu( ART_OFFSET / 2.0 ) * BOARD_SCALE );
524  }
525 
526  // VRML_LAYER m_top_silk;
527  aModel.m_top_silk.Tesselate( &aModel.m_holes );
528 
529  if( USE_INLINES )
530  {
531  write_triangle_bag( *aOutputFile, aModel.GetColor( VRML_COLOR_SILK ), &aModel.m_top_silk,
532  true, true, aModel.GetLayerZ( F_SilkS ), 0 );
533  }
534  else
535  {
537  aModel.GetLayerZ( F_SilkS ), true );
538  }
539 
540  // VRML_LAYER m_bot_silk;
541  aModel.m_bot_silk.Tesselate( &aModel.m_holes );
542 
543  if( USE_INLINES )
544  {
545  write_triangle_bag( *aOutputFile, aModel.GetColor( VRML_COLOR_SILK ), &aModel.m_bot_silk,
546  true, false, aModel.GetLayerZ( B_SilkS ), 0 );
547  }
548  else
549  {
551  aModel.GetLayerZ( B_SilkS ), false );
552  }
553 
554  if( !USE_INLINES )
555  S3D::WriteVRML( aFileName, true, aModel.m_OutputPCB.GetRawPtr(), true, true );
556 }
557 
558 
559 static void compute_layer_Zs( MODEL_VRML& aModel, BOARD* pcb )
560 {
561  int copper_layers = pcb->GetCopperLayerCount();
562 
563  // We call it 'layer' thickness, but it's the whole board thickness!
565  double half_thickness = aModel.m_brd_thickness / 2;
566 
567  // Compute each layer's Z value, more or less like the 3d view
568  for( LSEQ seq = LSET::AllCuMask().Seq(); seq; ++seq )
569  {
570  PCB_LAYER_ID i = *seq;
571 
572  if( i < copper_layers )
573  aModel.SetLayerZ( i, half_thickness - aModel.m_brd_thickness * i / (copper_layers - 1) );
574  else
575  aModel.SetLayerZ( i, - half_thickness ); // bottom layer
576  }
577 
578  /* To avoid rounding interference, we apply an epsilon to each
579  * successive layer */
580  double epsilon_z = Millimeter2iu( ART_OFFSET ) * BOARD_SCALE;
581  aModel.SetLayerZ( B_Paste, -half_thickness - epsilon_z * 4 );
582  aModel.SetLayerZ( B_Adhes, -half_thickness - epsilon_z * 3 );
583  aModel.SetLayerZ( B_SilkS, -half_thickness - epsilon_z * 2 );
584  aModel.SetLayerZ( B_Mask, -half_thickness - epsilon_z );
585  aModel.SetLayerZ( F_Mask, half_thickness + epsilon_z );
586  aModel.SetLayerZ( F_SilkS, half_thickness + epsilon_z * 2 );
587  aModel.SetLayerZ( F_Adhes, half_thickness + epsilon_z * 3 );
588  aModel.SetLayerZ( F_Paste, half_thickness + epsilon_z * 4 );
589  aModel.SetLayerZ( Dwgs_User, half_thickness + epsilon_z * 5 );
590  aModel.SetLayerZ( Cmts_User, half_thickness + epsilon_z * 6 );
591  aModel.SetLayerZ( Eco1_User, half_thickness + epsilon_z * 7 );
592  aModel.SetLayerZ( Eco2_User, half_thickness + epsilon_z * 8 );
593  aModel.SetLayerZ( Edge_Cuts, 0 );
594 }
595 
596 
597 static void export_vrml_line( MODEL_VRML& aModel, LAYER_NUM layer,
598  double startx, double starty,
599  double endx, double endy, double width )
600 {
601  VRML_LAYER* vlayer;
602 
603  if( !GetLayer( aModel, layer, &vlayer ) )
604  return;
605 
606  if( width < aModel.m_minLineWidth)
607  width = aModel.m_minLineWidth;
608 
609  starty = -starty;
610  endy = -endy;
611 
612  double angle = atan2( endy - starty, endx - startx ) * 180.0 / M_PI;
613  double length = Distance( startx, starty, endx, endy ) + width;
614  double cx = ( startx + endx ) / 2.0;
615  double cy = ( starty + endy ) / 2.0;
616 
617  if( !vlayer->AddSlot( cx, cy, length, width, angle, false ) )
618  throw( std::runtime_error( vlayer->GetError() ) );
619 }
620 
621 
622 static void export_vrml_circle( MODEL_VRML& aModel, LAYER_NUM layer,
623  double startx, double starty,
624  double endx, double endy, double width )
625 {
626  VRML_LAYER* vlayer;
627 
628  if( !GetLayer( aModel, layer, &vlayer ) )
629  return;
630 
631  if( width < aModel.m_minLineWidth )
632  width = aModel.m_minLineWidth;
633 
634  starty = -starty;
635  endy = -endy;
636 
637  double hole, radius;
638 
639  radius = Distance( startx, starty, endx, endy ) + ( width / 2);
640  hole = radius - width;
641 
642  if( !vlayer->AddCircle( startx, starty, radius, false ) )
643  throw( std::runtime_error( vlayer->GetError() ) );
644 
645  if( hole > 0.0001 )
646  {
647  if( !vlayer->AddCircle( startx, starty, hole, true ) )
648  throw( std::runtime_error( vlayer->GetError() ) );
649  }
650 }
651 
652 
653 static void export_vrml_arc( MODEL_VRML& aModel, LAYER_NUM layer,
654  double centerx, double centery,
655  double arc_startx, double arc_starty,
656  double width, double arc_angle )
657 {
658  VRML_LAYER* vlayer;
659 
660  if( !GetLayer( aModel, layer, &vlayer ) )
661  return;
662 
663  if( width < aModel.m_minLineWidth )
664  width = aModel.m_minLineWidth;
665 
666  centery = -centery;
667  arc_starty = -arc_starty;
668 
669  if( !vlayer->AddArc( centerx, centery, arc_startx, arc_starty, width, -arc_angle, false ) )
670  throw( std::runtime_error( vlayer->GetError() ) );
671 
672 }
673 
674 
675 static void export_vrml_drawsegment( MODEL_VRML& aModel, DRAWSEGMENT* drawseg )
676 {
677  LAYER_NUM layer = drawseg->GetLayer();
678  double w = drawseg->GetWidth() * BOARD_SCALE;
679  double x = drawseg->GetStart().x * BOARD_SCALE;
680  double y = drawseg->GetStart().y * BOARD_SCALE;
681  double xf = drawseg->GetEnd().x * BOARD_SCALE;
682  double yf = drawseg->GetEnd().y * BOARD_SCALE;
683  double r = sqrt( pow( x - xf, 2 ) + pow( y - yf, 2 ) );
684 
685  // Items on the edge layer are handled elsewhere; just return
686  if( layer == Edge_Cuts )
687  return;
688 
689  switch( drawseg->GetShape() )
690  {
691  case S_ARC:
692  export_vrml_arc( aModel, layer,
693  (double) drawseg->GetCenter().x * BOARD_SCALE,
694  (double) drawseg->GetCenter().y * BOARD_SCALE,
695  (double) drawseg->GetArcStart().x * BOARD_SCALE,
696  (double) drawseg->GetArcStart().y * BOARD_SCALE,
697  w, drawseg->GetAngle() / 10 );
698  break;
699 
700  case S_CIRCLE:
701  // Break circles into two 180 arcs to prevent the vrml hole from obscuring objects
702  // within the hole area of the circle.
703  export_vrml_arc( aModel, layer, x, y, x, y-r, w, 180.0 );
704  export_vrml_arc( aModel, layer, x, y, x, y+r, w, 180.0 );
705  break;
706 
707  default:
708  export_vrml_line( aModel, layer, x, y, xf, yf, w );
709  break;
710  }
711 }
712 
713 
714 /* C++ doesn't have closures and neither continuation forms... this is
715  * for coupling the vrml_text_callback with the common parameters */
716 static void vrml_text_callback( int x0, int y0, int xf, int yf )
717 {
718  LAYER_NUM m_text_layer = model_vrml->m_text_layer;
719  int m_text_width = model_vrml->m_text_width;
720 
721  export_vrml_line( *model_vrml, m_text_layer,
722  x0 * BOARD_SCALE, y0 * BOARD_SCALE,
723  xf * BOARD_SCALE, yf * BOARD_SCALE,
724  m_text_width * BOARD_SCALE );
725 }
726 
727 
728 static void export_vrml_pcbtext( MODEL_VRML& aModel, TEXTE_PCB* text )
729 {
730  model_vrml->m_text_layer = text->GetLayer();
731  model_vrml->m_text_width = text->GetThickness();
732 
733  wxSize size = text->GetTextSize();
734 
735  if( text->IsMirrored() )
736  size.x = -size.x;
737 
738  COLOR4D color = COLOR4D::BLACK; // not actually used, but needed by DrawGraphicText
739 
740  if( text->IsMultilineAllowed() )
741  {
742  wxArrayString strings_list;
743  wxStringSplit( text->GetShownText(), strings_list, '\n' );
744  std::vector<wxPoint> positions;
745  positions.reserve( strings_list.Count() );
746  text->GetPositionsOfLinesOfMultilineText( positions, strings_list.Count() );
747 
748  for( unsigned ii = 0; ii < strings_list.Count(); ii++ )
749  {
750  wxString& txt = strings_list.Item( ii );
751  DrawGraphicText( NULL, NULL, positions[ii], color,
752  txt, text->GetTextAngle(), size,
753  text->GetHorizJustify(), text->GetVertJustify(),
754  text->GetThickness(), text->IsItalic(),
755  true,
757  }
758  }
759  else
760  {
761  DrawGraphicText( NULL, NULL, text->GetTextPos(), color,
762  text->GetShownText(), text->GetTextAngle(), size,
763  text->GetHorizJustify(), text->GetVertJustify(),
764  text->GetThickness(), text->IsItalic(),
765  true,
767  }
768 }
769 
770 
771 static void export_vrml_drawings( MODEL_VRML& aModel, BOARD* pcb )
772 {
773  // draw graphic items
774  for( auto drawing : pcb->Drawings() )
775  {
776  PCB_LAYER_ID layer = drawing->GetLayer();
777 
778  if( layer != F_Cu && layer != B_Cu && layer != B_SilkS && layer != F_SilkS )
779  continue;
780 
781  switch( drawing->Type() )
782  {
783  case PCB_LINE_T:
784  export_vrml_drawsegment( aModel, (DRAWSEGMENT*) drawing );
785  break;
786 
787  case PCB_TEXT_T:
788  export_vrml_pcbtext( aModel, (TEXTE_PCB*) drawing );
789  break;
790 
791  default:
792  break;
793  }
794  }
795 }
796 
797 
798 // board edges and cutouts
799 static void export_vrml_board( MODEL_VRML& aModel, BOARD* aPcb )
800 {
801  SHAPE_POLY_SET pcbOutlines; // stores the board main outlines
802  wxString msg;
803 
804  if( !aPcb->GetBoardPolygonOutlines( pcbOutlines, &msg ) )
805  {
806  msg << "\n\n" <<
807  _( "Unable to calculate the board outlines; fall back to using the board boundary box." );
808  wxMessageBox( msg );
809  }
810 
811  int seg;
812 
813  for( int cnt = 0; cnt < pcbOutlines.OutlineCount(); cnt++ )
814  {
815  const SHAPE_LINE_CHAIN& outline = pcbOutlines.COutline( cnt );
816 
817  seg = aModel.m_board.NewContour();
818 
819  for( int j = 0; j < outline.PointCount(); j++ )
820  {
821  aModel.m_board.AddVertex( seg, (double)outline.CPoint(j).x * BOARD_SCALE,
822  -((double)outline.CPoint(j).y * BOARD_SCALE ) );
823 
824  }
825 
826  aModel.m_board.EnsureWinding( seg, false );
827 
828  // Generate holes:
829  for( int ii = 0; ii < pcbOutlines.HoleCount( cnt ); ii++ )
830  {
831  const SHAPE_LINE_CHAIN& hole = pcbOutlines.Hole( cnt, ii );
832 
833  seg = aModel.m_holes.NewContour();
834 
835  if( seg < 0 )
836  {
837  msg << "\n\n" <<
838  _( "VRML Export Failed: Could not add holes to contours." );
839  wxMessageBox( msg );
840 
841  return;
842  }
843 
844  for( int j = 0; j < hole.PointCount(); j++ )
845  {
846  aModel.m_holes.AddVertex( seg, (double)hole.CPoint(j).x * BOARD_SCALE,
847  -((double)hole.CPoint(j).y * BOARD_SCALE ) );
848 
849  }
850 
851  aModel.m_holes.EnsureWinding( seg, true );
852  }
853  }
854 }
855 
856 
857 static void export_round_padstack( MODEL_VRML& aModel, BOARD* pcb,
858  double x, double y, double r,
859  LAYER_NUM bottom_layer, LAYER_NUM top_layer,
860  double hole )
861 {
862  LAYER_NUM layer = top_layer;
863  bool thru = true;
864 
865  // if not a thru hole do not put a hole in the board
866  if( top_layer != F_Cu || bottom_layer != B_Cu )
867  thru = false;
868 
869  if( thru && hole > 0 )
870  aModel.m_holes.AddCircle( x, -y, hole, true );
871 
872  if( aModel.m_plainPCB )
873  return;
874 
875  while( 1 )
876  {
877  if( layer == B_Cu )
878  {
879  aModel.m_bot_copper.AddCircle( x, -y, r );
880 
881  if( hole > 0 && !thru )
882  aModel.m_bot_copper.AddCircle( x, -y, hole, true );
883 
884  }
885  else if( layer == F_Cu )
886  {
887  aModel.m_top_copper.AddCircle( x, -y, r );
888 
889  if( hole > 0 && !thru )
890  aModel.m_top_copper.AddCircle( x, -y, hole, true );
891 
892  }
893 
894  if( layer == bottom_layer )
895  break;
896 
897  layer = bottom_layer;
898  }
899 }
900 
901 
902 static void export_vrml_via( MODEL_VRML& aModel, BOARD* aPcb, const VIA* aVia )
903 {
904  double x, y, r, hole;
905  PCB_LAYER_ID top_layer, bottom_layer;
906 
907  hole = aVia->GetDrillValue() * BOARD_SCALE / 2.0;
908  r = aVia->GetWidth() * BOARD_SCALE / 2.0;
909  x = aVia->GetStart().x * BOARD_SCALE;
910  y = aVia->GetStart().y * BOARD_SCALE;
911  aVia->LayerPair( &top_layer, &bottom_layer );
912 
913  // do not render a buried via
914  if( top_layer != F_Cu && bottom_layer != B_Cu )
915  return;
916 
917  // Export the via padstack
918  export_round_padstack( aModel, aPcb, x, y, r, bottom_layer, top_layer, hole );
919 }
920 
921 
922 static void export_vrml_tracks( MODEL_VRML& aModel, BOARD* pcb )
923 {
924  for( TRACK* track = pcb->m_Track; track; track = track->Next() )
925  {
926  if( track->Type() == PCB_VIA_T )
927  {
928  export_vrml_via( aModel, pcb, (const VIA*) track );
929  }
930  else if( ( track->GetLayer() == B_Cu || track->GetLayer() == F_Cu )
931  && !aModel.m_plainPCB )
932  export_vrml_line( aModel, track->GetLayer(),
933  track->GetStart().x * BOARD_SCALE,
934  track->GetStart().y * BOARD_SCALE,
935  track->GetEnd().x * BOARD_SCALE,
936  track->GetEnd().y * BOARD_SCALE,
937  track->GetWidth() * BOARD_SCALE );
938  }
939 }
940 
941 
942 static void export_vrml_zones( MODEL_VRML& aModel, BOARD* aPcb )
943 {
944 
945  for( int ii = 0; ii < aPcb->GetAreaCount(); ii++ )
946  {
947  ZONE_CONTAINER* zone = aPcb->GetArea( ii );
948 
949  VRML_LAYER* vl;
950 
951  if( !GetLayer( aModel, zone->GetLayer(), &vl ) )
952  continue;
953 
954  if( !zone->IsFilled() )
955  {
956  zone->SetFillMode( 0 ); // use filled polygons
957  zone->BuildFilledSolidAreasPolygons( aPcb );
958  }
959 
960  const SHAPE_POLY_SET& poly = zone->GetFilledPolysList();
961 
962  for( int i = 0; i < poly.OutlineCount(); i++ )
963  {
964  const SHAPE_LINE_CHAIN& outline = poly.COutline( i );
965 
966  int seg = vl->NewContour();
967 
968  for( int j = 0; j < outline.PointCount(); j++ )
969  {
970  if( !vl->AddVertex( seg, (double)outline.CPoint( j ).x * BOARD_SCALE,
971  -((double)outline.CPoint( j ).y * BOARD_SCALE ) ) )
972  throw( std::runtime_error( vl->GetError() ) );
973 
974  }
975 
976  vl->EnsureWinding( seg, false );
977  }
978  }
979 }
980 
981 
982 static void export_vrml_text_module( TEXTE_MODULE* module )
983 {
984  if( module->IsVisible() )
985  {
986  wxSize size = module->GetTextSize();
987 
988  if( module->IsMirrored() )
989  size.x = -size.x; // Text is mirrored
990 
991  model_vrml->m_text_layer = module->GetLayer();
992  model_vrml->m_text_width = module->GetThickness();
993 
994  DrawGraphicText( NULL, NULL, module->GetTextPos(), BLACK,
995  module->GetShownText(), module->GetDrawRotation(), size,
996  module->GetHorizJustify(), module->GetVertJustify(),
997  module->GetThickness(), module->IsItalic(),
998  true,
1000  }
1001 }
1002 
1003 
1004 static void export_vrml_edge_module( MODEL_VRML& aModel, EDGE_MODULE* aOutline,
1005  double aOrientation )
1006 {
1007  LAYER_NUM layer = aOutline->GetLayer();
1008  double x = aOutline->GetStart().x * BOARD_SCALE;
1009  double y = aOutline->GetStart().y * BOARD_SCALE;
1010  double xf = aOutline->GetEnd().x * BOARD_SCALE;
1011  double yf = aOutline->GetEnd().y * BOARD_SCALE;
1012  double w = aOutline->GetWidth() * BOARD_SCALE;
1013 
1014  switch( aOutline->GetShape() )
1015  {
1016  case S_SEGMENT:
1017  export_vrml_line( aModel, layer, x, y, xf, yf, w );
1018  break;
1019 
1020  case S_ARC:
1021  export_vrml_arc( aModel, layer, x, y, xf, yf, w, aOutline->GetAngle() / 10 );
1022  break;
1023 
1024  case S_CIRCLE:
1025  export_vrml_circle( aModel, layer, x, y, xf, yf, w );
1026  break;
1027 
1028  case S_POLYGON:
1029  {
1030  VRML_LAYER* vl;
1031 
1032  if( !GetLayer( aModel, layer, &vl ) )
1033  break;
1034 
1035  int nvert = aOutline->GetPolyPoints().size() - 1;
1036  int i = 0;
1037 
1038  if( nvert < 3 ) break;
1039 
1040  int seg = vl->NewContour();
1041 
1042  if( seg < 0 )
1043  break;
1044 
1045  while( i < nvert )
1046  {
1047  CPolyPt corner( aOutline->GetPolyPoints()[i] );
1048  RotatePoint( &corner.x, &corner.y, aOrientation );
1049  corner.x += aOutline->GetPosition().x;
1050  corner.y += aOutline->GetPosition().y;
1051 
1052  x = corner.x * BOARD_SCALE;
1053  y = - ( corner.y * BOARD_SCALE );
1054 
1055  if( !vl->AddVertex( seg, x, y ) )
1056  throw( std::runtime_error( vl->GetError() ) );
1057 
1058  ++i;
1059  }
1060  vl->EnsureWinding( seg, false );
1061  }
1062  break;
1063 
1064  default:
1065  break;
1066  }
1067 }
1068 
1069 
1070 static void export_vrml_padshape( MODEL_VRML& aModel, VRML_LAYER* aTinLayer, D_PAD* aPad )
1071 {
1072  // The (maybe offset) pad position
1073  wxPoint pad_pos = aPad->ShapePos();
1074  double pad_x = pad_pos.x * BOARD_SCALE;
1075  double pad_y = pad_pos.y * BOARD_SCALE;
1076  wxSize pad_delta = aPad->GetDelta();
1077 
1078  double pad_dx = pad_delta.x * BOARD_SCALE / 2.0;
1079  double pad_dy = pad_delta.y * BOARD_SCALE / 2.0;
1080 
1081  double pad_w = aPad->GetSize().x * BOARD_SCALE / 2.0;
1082  double pad_h = aPad->GetSize().y * BOARD_SCALE / 2.0;
1083 
1084  switch( aPad->GetShape() )
1085  {
1086  case PAD_SHAPE_CIRCLE:
1087 
1088  if( !aTinLayer->AddCircle( pad_x, -pad_y, pad_w, false ) )
1089  throw( std::runtime_error( aTinLayer->GetError() ) );
1090 
1091  break;
1092 
1093  case PAD_SHAPE_OVAL:
1094 
1095  if( !aTinLayer->AddSlot( pad_x, -pad_y, pad_w * 2.0, pad_h * 2.0,
1096  aPad->GetOrientation()/10.0, false ) )
1097  throw( std::runtime_error( aTinLayer->GetError() ) );
1098 
1099  break;
1100 
1101  case PAD_SHAPE_RECT:
1102  // Just to be sure :D
1103  pad_dx = 0;
1104  pad_dy = 0;
1105 
1106  case PAD_SHAPE_TRAPEZOID:
1107  {
1108  double coord[8] =
1109  {
1110  -pad_w + pad_dy, -pad_h - pad_dx,
1111  -pad_w - pad_dy, pad_h + pad_dx,
1112  +pad_w - pad_dy, -pad_h + pad_dx,
1113  +pad_w + pad_dy, pad_h - pad_dx
1114  };
1115 
1116  for( int i = 0; i < 4; i++ )
1117  {
1118  RotatePoint( &coord[i * 2], &coord[i * 2 + 1], aPad->GetOrientation() );
1119  coord[i * 2] += pad_x;
1120  coord[i * 2 + 1] += pad_y;
1121  }
1122 
1123  int lines;
1124 
1125  lines = aTinLayer->NewContour();
1126 
1127  if( lines < 0 )
1128  throw( std::runtime_error( aTinLayer->GetError() ) );
1129 
1130  if( !aTinLayer->AddVertex( lines, coord[0], -coord[1] ) )
1131  throw( std::runtime_error( aTinLayer->GetError() ) );
1132 
1133  if( !aTinLayer->AddVertex( lines, coord[4], -coord[5] ) )
1134  throw( std::runtime_error( aTinLayer->GetError() ) );
1135 
1136  if( !aTinLayer->AddVertex( lines, coord[6], -coord[7] ) )
1137  throw( std::runtime_error( aTinLayer->GetError() ) );
1138 
1139  if( !aTinLayer->AddVertex( lines, coord[2], -coord[3] ) )
1140  throw( std::runtime_error( aTinLayer->GetError() ) );
1141 
1142  if( !aTinLayer->EnsureWinding( lines, false ) )
1143  throw( std::runtime_error( aTinLayer->GetError() ) );
1144 
1145  break;
1146  }
1147 
1148  default:
1149  break;
1150  }
1151 }
1152 
1153 
1154 static void export_vrml_pad( MODEL_VRML& aModel, BOARD* aPcb, D_PAD* aPad )
1155 {
1156  double hole_drill_w = (double) aPad->GetDrillSize().x * BOARD_SCALE / 2.0;
1157  double hole_drill_h = (double) aPad->GetDrillSize().y * BOARD_SCALE / 2.0;
1158  double hole_drill = std::min( hole_drill_w, hole_drill_h );
1159  double hole_x = aPad->GetPosition().x * BOARD_SCALE;
1160  double hole_y = aPad->GetPosition().y * BOARD_SCALE;
1161 
1162  // Export the hole on the edge layer
1163  if( hole_drill > 0 )
1164  {
1165  bool pth = false;
1166 
1167  if( ( aPad->GetAttribute() != PAD_ATTRIB_HOLE_NOT_PLATED )
1168  && !aModel.m_plainPCB )
1169  pth = true;
1170 
1171  if( aPad->GetDrillShape() == PAD_DRILL_SHAPE_OBLONG )
1172  {
1173  // Oblong hole (slot)
1174 
1175  if( pth )
1176  {
1177  aModel.m_holes.AddSlot( hole_x, -hole_y, hole_drill_w * 2.0 + PLATE_OFFSET,
1178  hole_drill_h * 2.0 + PLATE_OFFSET,
1179  aPad->GetOrientation()/10.0, true, true );
1180 
1181  aModel.m_plated_holes.AddSlot( hole_x, -hole_y,
1182  hole_drill_w * 2.0, hole_drill_h * 2.0,
1183  aPad->GetOrientation()/10.0, true, false );
1184  }
1185  else
1186  {
1187  aModel.m_holes.AddSlot( hole_x, -hole_y, hole_drill_w * 2.0, hole_drill_h * 2.0,
1188  aPad->GetOrientation()/10.0, true, false );
1189 
1190  }
1191  }
1192  else
1193  {
1194  // Drill a round hole
1195 
1196  if( pth )
1197  {
1198  aModel.m_holes.AddCircle( hole_x, -hole_y, hole_drill + PLATE_OFFSET, true, true );
1199  aModel.m_plated_holes.AddCircle( hole_x, -hole_y, hole_drill, true, false );
1200  }
1201  else
1202  {
1203  aModel.m_holes.AddCircle( hole_x, -hole_y, hole_drill, true, false );
1204  }
1205 
1206  }
1207  }
1208 
1209  if( aModel.m_plainPCB )
1210  return;
1211 
1212  // The pad proper, on the selected layers
1213  LSET layer_mask = aPad->GetLayerSet();
1214 
1215  if( layer_mask[B_Cu] )
1216  {
1217  export_vrml_padshape( aModel, &aModel.m_bot_tin, aPad );
1218  }
1219 
1220  if( layer_mask[F_Cu] )
1221  {
1222  export_vrml_padshape( aModel, &aModel.m_top_tin, aPad );
1223  }
1224 }
1225 
1226 
1227 // From axis/rot to quaternion
1228 static void build_quat( double x, double y, double z, double a, double q[4] )
1229 {
1230  double sina = sin( a / 2 );
1231 
1232  q[0] = x * sina;
1233  q[1] = y * sina;
1234  q[2] = z * sina;
1235  q[3] = cos( a / 2 );
1236 }
1237 
1238 
1239 // From quaternion to axis/rot
1240 static void from_quat( double q[4], double rot[4] )
1241 {
1242  rot[3] = acos( q[3] ) * 2;
1243 
1244  for( int i = 0; i < 3; i++ )
1245  {
1246  rot[i] = q[i] / sin( rot[3] / 2 );
1247  }
1248 }
1249 
1250 
1251 // Quaternion composition
1252 static void compose_quat( double q1[4], double q2[4], double qr[4] )
1253 {
1254  double tmp[4];
1255 
1256  tmp[0] = q2[3] * q1[0] + q2[0] * q1[3] + q2[1] * q1[2] - q2[2] * q1[1];
1257  tmp[1] = q2[3] * q1[1] + q2[1] * q1[3] + q2[2] * q1[0] - q2[0] * q1[2];
1258  tmp[2] = q2[3] * q1[2] + q2[2] * q1[3] + q2[0] * q1[1] - q2[1] * q1[0];
1259  tmp[3] = q2[3] * q1[3] - q2[0] * q1[0] - q2[1] * q1[1] - q2[2] * q1[2];
1260 
1261  qr[0] = tmp[0];
1262  qr[1] = tmp[1];
1263  qr[2] = tmp[2];
1264  qr[3] = tmp[3];
1265 }
1266 
1267 
1268 static void export_vrml_module( MODEL_VRML& aModel, BOARD* aPcb,
1269  MODULE* aModule, std::ostream* aOutputFile )
1270 {
1271  if( !aModel.m_plainPCB )
1272  {
1273  // Reference and value
1274  if( aModule->Reference().IsVisible() )
1275  export_vrml_text_module( &aModule->Reference() );
1276 
1277  if( aModule->Value().IsVisible() )
1278  export_vrml_text_module( &aModule->Value() );
1279 
1280  // Export module edges
1281  for( EDA_ITEM* item = aModule->GraphicalItemsList(); item; item = item->Next() )
1282  {
1283  switch( item->Type() )
1284  {
1285  case PCB_MODULE_TEXT_T:
1286  export_vrml_text_module( static_cast<TEXTE_MODULE*>( item ) );
1287  break;
1288 
1289  case PCB_MODULE_EDGE_T:
1290  export_vrml_edge_module( aModel, static_cast<EDGE_MODULE*>( item ),
1291  aModule->GetOrientation() );
1292  break;
1293 
1294  default:
1295  break;
1296  }
1297  }
1298  }
1299 
1300  // Export pads
1301  for( D_PAD* pad = aModule->PadsList(); pad; pad = pad->Next() )
1302  export_vrml_pad( aModel, aPcb, pad );
1303 
1304  bool isFlipped = aModule->GetLayer() == B_Cu;
1305 
1306  // Export the object VRML model(s)
1307  std::list<S3D_INFO>::iterator sM = aModule->Models().begin();
1308  std::list<S3D_INFO>::iterator eM = aModule->Models().end();
1309 
1310  wxFileName subdir( SUBDIR_3D, "" );
1311 
1312  while( sM != eM )
1313  {
1314  SGNODE* mod3d = (SGNODE*) cache->Load( sM->m_Filename );
1315 
1316  if( NULL == mod3d )
1317  {
1318  ++sM;
1319  continue;
1320  }
1321 
1322  /* Calculate 3D shape rotation:
1323  * this is the rotation parameters, with an additional 180 deg rotation
1324  * for footprints that are flipped
1325  * When flipped, axis rotation is the horizontal axis (X axis)
1326  */
1327  double rotx = -sM->m_Rotation.x;
1328  double roty = -sM->m_Rotation.y;
1329  double rotz = -sM->m_Rotation.z;
1330 
1331  if( isFlipped )
1332  {
1333  rotx += 180.0;
1334  roty = -roty;
1335  rotz = -rotz;
1336  }
1337 
1338  // Do some quaternion munching
1339  double q1[4], q2[4], rot[4];
1340  build_quat( 1, 0, 0, DEG2RAD( rotx ), q1 );
1341  build_quat( 0, 1, 0, DEG2RAD( roty ), q2 );
1342  compose_quat( q1, q2, q1 );
1343  build_quat( 0, 0, 1, DEG2RAD( rotz ), q2 );
1344  compose_quat( q1, q2, q1 );
1345 
1346  // Note here aModule->GetOrientation() is in 0.1 degrees,
1347  // so module rotation has to be converted to radians
1348  build_quat( 0, 0, 1, DECIDEG2RAD( aModule->GetOrientation() ), q2 );
1349  compose_quat( q1, q2, q1 );
1350  from_quat( q1, rot );
1351 
1352  // adjust 3D shape local offset position
1353  // they are given in inch, so they are converted in board IU.
1354  double offsetx = sM->m_Offset.x * IU_PER_MILS * 1000.0;
1355  double offsety = sM->m_Offset.y * IU_PER_MILS * 1000.0;
1356  double offsetz = sM->m_Offset.z * IU_PER_MILS * 1000.0;
1357 
1358  if( isFlipped )
1359  offsetz = -offsetz;
1360  else // In normal mode, Y axis is reversed in Pcbnew.
1361  offsety = -offsety;
1362 
1363  RotatePoint( &offsetx, &offsety, aModule->GetOrientation() );
1364 
1365  SGPOINT trans;
1366  trans.x = ( offsetx + aModule->GetPosition().x ) * BOARD_SCALE + aModel.m_tx;
1367  trans.y = -(offsety + aModule->GetPosition().y) * BOARD_SCALE - aModel.m_ty;
1368  trans.z = (offsetz * BOARD_SCALE ) + aModel.GetLayerZ( aModule->GetLayer() );
1369 
1370  if( USE_INLINES )
1371  {
1372  wxFileName srcFile = cache->GetResolver()->ResolvePath( sM->m_Filename );
1373  wxFileName dstFile;
1374  dstFile.SetPath( SUBDIR_3D );
1375  dstFile.SetName( srcFile.GetName() );
1376  dstFile.SetExt( "wrl" );
1377 
1378  // copy the file if necessary
1379  wxDateTime srcModTime = srcFile.GetModificationTime();
1380  wxDateTime destModTime = srcModTime;
1381 
1382  destModTime.SetToCurrent();
1383 
1384  if( dstFile.FileExists() )
1385  destModTime = dstFile.GetModificationTime();
1386 
1387  if( srcModTime != destModTime )
1388  {
1389  wxLogDebug( "Copying 3D model %s to %s.",
1390  GetChars( srcFile.GetFullPath() ),
1391  GetChars( dstFile.GetFullPath() ) );
1392 
1393  wxString fileExt = srcFile.GetExt();
1394  fileExt.LowerCase();
1395 
1396  // copy VRML models and use the scenegraph library to
1397  // translate other model types
1398  if( fileExt == "wrl" )
1399  {
1400  if( !wxCopyFile( srcFile.GetFullPath(), dstFile.GetFullPath() ) )
1401  continue;
1402  }
1403  else
1404  {
1405  if( !S3D::WriteVRML( dstFile.GetFullPath().ToUTF8(), true, mod3d, USE_DEFS, true ) )
1406  continue;
1407  }
1408  }
1409 
1410  (*aOutputFile) << "Transform {\n";
1411 
1412  // only write a rotation if it is >= 0.1 deg
1413  if( std::abs( rot[3] ) > 0.0001745 )
1414  {
1415  (*aOutputFile) << " rotation " << std::setprecision( 5 );
1416  (*aOutputFile) << rot[0] << " " << rot[1] << " " << rot[2] << " " << rot[3] << "\n";
1417  }
1418 
1419  (*aOutputFile) << " translation " << std::setprecision( PRECISION );
1420  (*aOutputFile) << trans.x << " ";
1421  (*aOutputFile) << trans.y << " ";
1422  (*aOutputFile) << trans.z << "\n";
1423 
1424  (*aOutputFile) << " scale ";
1425  (*aOutputFile) << sM->m_Scale.x << " ";
1426  (*aOutputFile) << sM->m_Scale.y << " ";
1427  (*aOutputFile) << sM->m_Scale.z << "\n";
1428 
1429  (*aOutputFile) << " children [\n Inline {\n url \"";
1430 
1431  if( USE_RELPATH )
1432  {
1433  wxFileName tmp = dstFile;
1434  tmp.SetExt( "" );
1435  tmp.SetName( "" );
1436  tmp.RemoveLastDir();
1437  dstFile.MakeRelativeTo( tmp.GetPath() );
1438  }
1439 
1440  wxString fn = dstFile.GetFullPath();
1441  fn.Replace( "\\", "/" );
1442  (*aOutputFile) << TO_UTF8( fn ) << "\"\n } ]\n";
1443  (*aOutputFile) << " }\n";
1444  }
1445  else
1446  {
1447  IFSG_TRANSFORM* modelShape = new IFSG_TRANSFORM( aModel.m_OutputPCB.GetRawPtr() );
1448 
1449  // only write a rotation if it is >= 0.1 deg
1450  if( std::abs( rot[3] ) > 0.0001745 )
1451  modelShape->SetRotation( SGVECTOR( rot[0], rot[1], rot[2] ), rot[3] );
1452 
1453  modelShape->SetTranslation( trans );
1454  modelShape->SetScale( SGPOINT( sM->m_Scale.x, sM->m_Scale.y, sM->m_Scale.z ) );
1455 
1456  if( NULL == S3D::GetSGNodeParent( mod3d ) )
1457  {
1458  aModel.m_components.push_back( mod3d );
1459  modelShape->AddChildNode( mod3d );
1460  }
1461  else
1462  {
1463  modelShape->AddRefNode( mod3d );
1464  }
1465 
1466  }
1467 
1468  ++sM;
1469  }
1470 }
1471 
1472 
1473 bool PCB_EDIT_FRAME::ExportVRML_File( const wxString& aFullFileName, double aMMtoWRMLunit,
1474  bool aExport3DFiles, bool aUseRelativePaths,
1475  bool aUsePlainPCB, const wxString& a3D_Subdir,
1476  double aXRef, double aYRef )
1477 {
1478  BOARD* pcb = GetBoard();
1479  bool ok = true;
1480 
1481  USE_INLINES = aExport3DFiles;
1482  USE_DEFS = true;
1483  USE_RELPATH = aUseRelativePaths;
1484 
1485  cache = Prj().Get3DCacheManager();
1486  PROJ_DIR = Prj().GetProjectPath();
1487  SUBDIR_3D = a3D_Subdir;
1488  MODEL_VRML model3d;
1489  model_vrml = &model3d;
1490  model3d.SetScale( aMMtoWRMLunit );
1491 
1492  if( USE_INLINES )
1493  {
1494  BOARD_SCALE = MM_PER_IU / 2.54;
1495  model3d.SetOffset( -aXRef / 2.54, aYRef / 2.54 );
1496  }
1497  else
1498  {
1499  BOARD_SCALE = MM_PER_IU;
1500  model3d.SetOffset( -aXRef, aYRef );
1501  }
1502 
1503  // plain PCB or else PCB with copper and silkscreen
1504  model3d.m_plainPCB = aUsePlainPCB;
1505 
1506  try
1507  {
1508 
1509  // Preliminary computation: the z value for each layer
1510  compute_layer_Zs(model3d, pcb);
1511 
1512  // board edges and cutouts
1513  export_vrml_board(model3d, pcb);
1514 
1515  // Drawing and text on the board
1516  if( !aUsePlainPCB )
1517  export_vrml_drawings( model3d, pcb );
1518 
1519  // Export vias and trackage
1520  export_vrml_tracks( model3d, pcb );
1521 
1522  // Export zone fills
1523  if( !aUsePlainPCB )
1524  export_vrml_zones( model3d, pcb);
1525 
1526  if( USE_INLINES )
1527  {
1528  // check if the 3D Subdir exists - create if not
1529  wxFileName subdir( SUBDIR_3D, "" );
1530 
1531  if( ! subdir.DirExists() )
1532  {
1533  if( !wxDir::Make( subdir.GetFullPath() ) )
1534  throw( std::runtime_error( "Could not create 3D model subdirectory" ) );
1535  }
1536 
1537  OPEN_OSTREAM( output_file, TO_UTF8( aFullFileName ) );
1538 
1539  if( output_file.fail() )
1540  {
1541  std::ostringstream ostr;
1542  ostr << "Could not open file '" << TO_UTF8( aFullFileName ) << "'";
1543  throw( std::runtime_error( ostr.str().c_str() ) );
1544  }
1545 
1546  output_file.imbue( std::locale( "C" ) );
1547 
1548  // Begin with the usual VRML boilerplate
1549  wxString fn = aFullFileName;
1550  fn.Replace( "\\" , "/" );
1551  output_file << "#VRML V2.0 utf8\n";
1552  output_file << "WorldInfo {\n";
1553  output_file << " title \"" << TO_UTF8( fn ) << " - Generated by Pcbnew\"\n";
1554  output_file << "}\n";
1555  output_file << "Transform {\n";
1556  output_file << " scale " << std::setprecision( PRECISION );
1557  output_file << WORLD_SCALE << " ";
1558  output_file << WORLD_SCALE << " ";
1559  output_file << WORLD_SCALE << "\n";
1560  output_file << " children [\n";
1561 
1562  // Export footprints
1563  for( MODULE* module = pcb->m_Modules; module != 0; module = module->Next() )
1564  export_vrml_module( model3d, pcb, module, &output_file );
1565 
1566  // write out the board and all layers
1567  write_layers( model3d, pcb, TO_UTF8( aFullFileName ), &output_file );
1568 
1569  // Close the outer 'transform' node
1570  output_file << "]\n}\n";
1571 
1572  CLOSE_STREAM( output_file );
1573  }
1574  else
1575  {
1576  // Export footprints
1577  for( MODULE* module = pcb->m_Modules; module != 0; module = module->Next() )
1578  export_vrml_module( model3d, pcb, module, NULL );
1579 
1580  // write out the board and all layers
1581  write_layers( model3d, pcb, TO_UTF8( aFullFileName ), NULL );
1582  }
1583  }
1584  catch( const std::exception& e )
1585  {
1586  wxString msg;
1587  msg << _( "IDF Export Failed:\n" ) << FROM_UTF8( e.what() );
1588  wxMessageBox( msg );
1589 
1590  ok = false;
1591  }
1592 
1593  return ok;
1594 }
1595 
1596 
1598 {
1599  if( colorIdx == -1 )
1600  colorIdx = VRML_COLOR_PCB;
1601  else if( colorIdx == VRML_COLOR_LAST )
1602  return NULL;
1603 
1604  if( sgmaterial[colorIdx] )
1605  return sgmaterial[colorIdx];
1606 
1607  IFSG_APPEARANCE vcolor( (SGNODE*) NULL );
1608  VRML_COLOR* cp = &colors[colorIdx];
1609 
1610  vcolor.SetSpecular( cp->spec_red, cp->spec_grn, cp->spec_blu );
1611  vcolor.SetDiffuse( cp->diffuse_red, cp->diffuse_grn, cp->diffuse_blu );
1612  vcolor.SetShininess( cp->shiny );
1613  // NOTE: XXX - replace with a better equation; using this definition
1614  // of ambient will not yield the best results
1615  vcolor.SetAmbient( cp->ambient, cp->ambient, cp->ambient );
1616  vcolor.SetTransparency( cp->transp );
1617 
1618  sgmaterial[colorIdx] = vcolor.GetRawPtr();
1619 
1620  return sgmaterial[colorIdx];
1621 };
1622 
1623 
1624 static void create_vrml_plane( IFSG_TRANSFORM& PcbOutput, VRML_COLOR_INDEX colorID,
1625  VRML_LAYER* layer, double top_z, bool aTopPlane )
1626 {
1627  std::vector< double > vertices;
1628  std::vector< int > idxPlane;
1629  std::vector< int > idxSide;
1630 
1631  if( !(*layer).Get2DTriangles( vertices, idxPlane, top_z, aTopPlane ) )
1632  {
1633 #ifdef DEBUG
1634  do {
1635  std::ostringstream ostr;
1636  ostr << __FILE__ << ": " << __FUNCTION__ << ": " << __LINE__ << "\n";
1637  ostr << " * [INFO] no vertex data";
1638  wxLogDebug( "%s\n", ostr.str().c_str() );
1639  } while( 0 );
1640 #endif
1641 
1642  return;
1643  }
1644 
1645  if( ( idxPlane.size() % 3 ) || ( idxSide.size() % 3 ) )
1646  {
1647 #ifdef DEBUG
1648  do {
1649  std::ostringstream ostr;
1650  ostr << __FILE__ << ": " << __FUNCTION__ << ": " << __LINE__ << "\n";
1651  ostr << " * [BUG] index lists are not a multiple of 3 (not a triangle list)";
1652  wxLogDebug( "%s\n", ostr.str().c_str() );
1653  } while( 0 );
1654 #endif
1655 
1656  throw( std::runtime_error( "[BUG] index lists are not a multiple of 3 (not a triangle list)" ) );
1657  }
1658 
1659  std::vector< SGPOINT > vlist;
1660  size_t nvert = vertices.size() / 3;
1661  size_t j = 0;
1662 
1663  for( size_t i = 0; i < nvert; ++i, j+= 3 )
1664  vlist.push_back( SGPOINT( vertices[j], vertices[j+1], vertices[j+2] ) );
1665 
1666  // create the intermediate scenegraph
1667  IFSG_TRANSFORM tx0( PcbOutput.GetRawPtr() ); // tx0 = Transform for this outline
1668  IFSG_SHAPE shape( tx0 ); // shape will hold (a) all vertices and (b) a local list of normals
1669  IFSG_FACESET face( shape ); // this face shall represent the top and bottom planes
1670  IFSG_COORDS cp( face ); // coordinates for all faces
1671  cp.SetCoordsList( nvert, &vlist[0] );
1672  IFSG_COORDINDEX coordIdx( face ); // coordinate indices for top and bottom planes only
1673  coordIdx.SetIndices( idxPlane.size(), &idxPlane[0] );
1674  IFSG_NORMALS norms( face ); // normals for the top and bottom planes
1675 
1676  // set the normals
1677  if( aTopPlane )
1678  {
1679  for( size_t i = 0; i < nvert; ++i )
1680  norms.AddNormal( 0.0, 0.0, 1.0 );
1681  }
1682  else
1683  {
1684  for( size_t i = 0; i < nvert; ++i )
1685  norms.AddNormal( 0.0, 0.0, -1.0 );
1686  }
1687 
1688  // assign a color from the palette
1689  SGNODE* modelColor = getSGColor( colorID );
1690 
1691  if( NULL != modelColor )
1692  {
1693  if( NULL == S3D::GetSGNodeParent( modelColor ) )
1694  shape.AddChildNode( modelColor );
1695  else
1696  shape.AddRefNode( modelColor );
1697  }
1698 
1699  return;
1700 }
1701 
1702 
1703 static void create_vrml_shell( IFSG_TRANSFORM& PcbOutput, VRML_COLOR_INDEX colorID,
1704  VRML_LAYER* layer, double top_z, double bottom_z )
1705 {
1706  std::vector< double > vertices;
1707  std::vector< int > idxPlane;
1708  std::vector< int > idxSide;
1709 
1710  if( top_z < bottom_z )
1711  {
1712  double tmp = top_z;
1713  top_z = bottom_z;
1714  bottom_z = tmp;
1715  }
1716 
1717  if( !(*layer).Get3DTriangles( vertices, idxPlane, idxSide, top_z, bottom_z ) )
1718  {
1719 #ifdef DEBUG
1720  do {
1721  std::ostringstream ostr;
1722  ostr << __FILE__ << ": " << __FUNCTION__ << ": " << __LINE__ << "\n";
1723  ostr << " * [INFO] no vertex data";
1724  wxLogDebug( "%s\n", ostr.str().c_str() );
1725  } while( 0 );
1726 #endif
1727 
1728  return;
1729  }
1730 
1731  if( ( idxPlane.size() % 3 ) || ( idxSide.size() % 3 ) )
1732  {
1733 #ifdef DEBUG
1734  do {
1735  std::ostringstream ostr;
1736  ostr << __FILE__ << ": " << __FUNCTION__ << ": " << __LINE__ << "\n";
1737  ostr << " * [BUG] index lists are not a multiple of 3 (not a triangle list)";
1738  wxLogDebug( "%s\n", ostr.str().c_str() );
1739  } while( 0 );
1740 #endif
1741 
1742  throw( std::runtime_error( "[BUG] index lists are not a multiple of 3 (not a triangle list)" ) );
1743  }
1744 
1745  std::vector< SGPOINT > vlist;
1746  size_t nvert = vertices.size() / 3;
1747  size_t j = 0;
1748 
1749  for( size_t i = 0; i < nvert; ++i, j+= 3 )
1750  vlist.push_back( SGPOINT( vertices[j], vertices[j+1], vertices[j+2] ) );
1751 
1752  // create the intermediate scenegraph
1753  IFSG_TRANSFORM tx0( PcbOutput.GetRawPtr() ); // tx0 = Transform for this outline
1754  IFSG_SHAPE shape( tx0 ); // shape will hold (a) all vertices and (b) a local list of normals
1755  IFSG_FACESET face( shape ); // this face shall represent the top and bottom planes
1756  IFSG_COORDS cp( face ); // coordinates for all faces
1757  cp.SetCoordsList( nvert, &vlist[0] );
1758  IFSG_COORDINDEX coordIdx( face ); // coordinate indices for top and bottom planes only
1759  coordIdx.SetIndices( idxPlane.size(), &idxPlane[0] );
1760  IFSG_NORMALS norms( face ); // normals for the top and bottom planes
1761 
1762  // number of TOP (and bottom) vertices
1763  j = nvert / 2;
1764 
1765  // set the TOP normals
1766  for( size_t i = 0; i < j; ++i )
1767  norms.AddNormal( 0.0, 0.0, 1.0 );
1768 
1769  // set the BOTTOM normals
1770  for( size_t i = 0; i < j; ++i )
1771  norms.AddNormal( 0.0, 0.0, -1.0 );
1772 
1773  // assign a color from the palette
1774  SGNODE* modelColor = getSGColor( colorID );
1775 
1776  if( NULL != modelColor )
1777  {
1778  if( NULL == S3D::GetSGNodeParent( modelColor ) )
1779  shape.AddChildNode( modelColor );
1780  else
1781  shape.AddRefNode( modelColor );
1782  }
1783 
1784  // create a second shape describing the vertical walls of the extrusion
1785  // using per-vertex-per-face-normals
1786  shape.NewNode( tx0 );
1787  shape.AddRefNode( modelColor ); // set the color to be the same as the top/bottom
1788  face.NewNode( shape );
1789  cp.NewNode( face ); // new vertex list
1790  norms.NewNode( face ); // new normals list
1791  coordIdx.NewNode( face ); // new index list
1792 
1793  // populate the new per-face vertex list and its indices and normals
1794  std::vector< int >::iterator sI = idxSide.begin();
1795  std::vector< int >::iterator eI = idxSide.end();
1796 
1797  size_t sidx = 0; // index to the new coord set
1798  SGPOINT p1, p2, p3;
1799  SGVECTOR vnorm;
1800 
1801  while( sI != eI )
1802  {
1803  p1 = vlist[*sI];
1804  cp.AddCoord( p1 );
1805  ++sI;
1806 
1807  p2 = vlist[*sI];
1808  cp.AddCoord( p2 );
1809  ++sI;
1810 
1811  p3 = vlist[*sI];
1812  cp.AddCoord( p3 );
1813  ++sI;
1814 
1815  vnorm.SetVector( S3D::CalcTriNorm( p1, p2, p3 ) );
1816  norms.AddNormal( vnorm );
1817  norms.AddNormal( vnorm );
1818  norms.AddNormal( vnorm );
1819 
1820  coordIdx.AddIndex( (int)sidx );
1821  ++sidx;
1822  coordIdx.AddIndex( (int)sidx );
1823  ++sidx;
1824  coordIdx.AddIndex( (int)sidx );
1825  ++sidx;
1826  }
1827 }
void SetLayerZ(LAYER_NUM aLayer, double aValue)
void wxStringSplit(const wxString &aText, wxArrayString &aStrings, wxChar aSplitter)
Function wxStringSplit splits aString to a string list separated at aSplitter.
Definition: common.cpp:137
static LSET AllCuMask(int aCuLayerCount=MAX_CU_LAYERS)
Function AllCuMask returns a mask holding the requested number of Cu PCB_LAYER_IDs.
Definition: lset.cpp:646
bool SetTranslation(const SGPOINT &aTranslation)
#define DIM(x)
of elements in an array
Definition: macros.h:98
static double BOARD_SCALE
Definition: export_vrml.cpp:65
static void export_vrml_pad(MODEL_VRML &aModel, BOARD *aPcb, D_PAD *aPad)
SGNODE * GetRawPtr(void)
Function GetRawPtr() returns the raw internal SGNODE pointer.
Definition: ifsg_node.cpp:66
Class ZONE_CONTAINER handles a list of polygons defining a copper zone.
Definition: class_zone.h:78
void DrawGraphicText(EDA_RECT *aClipBox, wxDC *aDC, const wxPoint &aPos, COLOR4D aColor, const wxString &aText, double aOrient, const wxSize &aSize, enum EDA_TEXT_HJUSTIFY_T aH_justify, enum EDA_TEXT_VJUSTIFY_T aV_justify, int aWidth, bool aItalic, bool aBold, void(*aCallback)(int x0, int y0, int xf, int yf), PLOTTER *aPlotter)
Function DrawGraphicText Draw a graphic text (like module texts)
Definition: drawtxt.cpp:122
TEXTE_MODULE & Reference()
Definition: class_module.h:463
static S3D_CACHE * cache
Definition: export_vrml.cpp:60
double x
Definition: sg_base.h:70
VRML_COLOR_INDEX
bool IsMultilineAllowed() const
Definition: eda_text.h:188
double GetDrawRotation() const
bool NewNode(SGNODE *aParent) override
Function NewNode creates a new node to associate with this wrapper.
static wxString FROM_UTF8(const char *cstring)
function FROM_UTF8 converts a UTF8 encoded C string to a wxString for all wxWidgets build modes...
Definition: macros.h:53
static void compose_quat(double q1[4], double q2[4], double qr[4])
PAD_ATTR_T GetAttribute() const
Definition: class_pad.h:381
TEXTE_PCB class definition.
static double WORLD_SCALE
Definition: export_vrml.cpp:64
const wxPoint & GetTextPos() const
Definition: eda_text.h:224
Class IFSG_COORDS is the wrapper for SGCOORDS.
Definition: ifsg_coords.h:40
bool IsItalic() const
Definition: eda_text.h:170
Class IFSG_COORDINDEX is the wrapper for SGCOORDINDEX.
like PAD_STANDARD, but not plated mechanical use only, no connection allowed
Definition: pad_shapes.h:65
static bool USE_INLINES
Definition: export_vrml.cpp:61
bool GetBoardPolygonOutlines(SHAPE_POLY_SET &aOutlines, wxString *aErrorText=NULL)
Function GetBoardPolygonOutlines Extracts the board outlines and build a closed polygon from lines...
const wxPoint GetCenter() const override
Function GetCenter()
bool Attach(SGNODE *aNode) override
Function Attach associates a given SGNODE* with this wrapper.
virtual PCB_LAYER_ID GetLayer() const
Function GetLayer returns the primary layer this item is on.
int PointCount() const
Function PointCount()
float transp
Definition: export_vrml.cpp:85
VRML_LAYER m_bot_tin
VRML_LAYER m_plated_holes
bool BuildFilledSolidAreasPolygons(BOARD *aPcb, SHAPE_POLY_SET *aOutlineBuffer=NULL)
Build the filled solid areas polygons from zone outlines (stored in m_Poly) The solid areas can be mo...
VRML_LAYER m_holes
Class BOARD to handle a board.
const wxPoint & GetPosition() const override
Definition: class_module.h:155
bool IsFilled() const
Definition: class_zone.h:215
polygon (not yet used for tracks, but could be in microwave apps)
bool SetDiffuse(float aRVal, float aGVal, float aBVal)
bool SetTransparency(float aTransparency)
static void create_vrml_plane(IFSG_TRANSFORM &PcbOutput, VRML_COLOR_INDEX colorID, VRML_LAYER *layer, double aHeight, bool aTopPlane)
MODULE * Next() const
Definition: class_module.h:100
#define OSTREAM
Definition: streamwrapper.h:99
int GetCopperLayerCount() const
Function GetCopperLayerCount.
int HoleCount(int aOutline) const
Returns the number of holes in a given outline
virtual PCB_LAYER_ID GetLayer() const override
Function GetLayer returns the primary layer this item is on.
Definition: class_zone.cpp:182
bool AddRefNode(SGNODE *aNode)
Function AddRefNode adds a reference to an existing node which is not owned by (not a child of) this ...
Definition: ifsg_node.cpp:199
class TEXTE_PCB, text on a layer
Definition: typeinfo.h:104
static MODEL_VRML * model_vrml
void SetVector(double aXVal, double aYVal, double aZVal)
Definition: sg_base.cpp:292
SHAPE_LINE_CHAIN & Hole(int aOutline, int aHole)
Returns the reference to aHole-th hole in the aIndex-th outline
void SetOffset(double aXoff, double aYoff)
BOARD * GetBoard() const
static void compute_layer_Zs(MODEL_VRML &aModel, BOARD *pcb)
Classes to handle copper zones.
PAD_DRILL_SHAPE_T GetDrillShape() const
Definition: class_pad.h:364
usual segment : line with rounded ends
SGLIB_API SGNODE * GetSGNodeParent(SGNODE *aNode)
Definition: ifsg_api.cpp:636
static void write_triangle_bag(std::ostream &aOut_file, VRML_COLOR &aColor, VRML_LAYER *aLayer, bool aPlane, bool aTop, double aTop_z, double aBottom_z)
const std::vector< wxPoint > & GetPolyPoints() const
void RotatePoint(int *pX, int *pY, double angle)
Definition: trigo.cpp:317
bool SetParent(SGNODE *aParent)
Function SetParent sets the parent SGNODE of this object.
Definition: ifsg_node.cpp:108
int OutlineCount() const
Returns the number of outlines in the set
static SGNODE * sgmaterial[VRML_COLOR_LAST]
std::list< S3D_INFO > & Models()
Definition: class_module.h:150
Class SGNODE represents the base class of all Scene Graph nodes.
Definition: sg_node.h:76
const wxSize & GetDrillSize() const
Definition: class_pad.h:261
collects header files for all SG* wrappers and the API
virtual wxString GetShownText() const override
Returns the string actually shown after processing of the base text.
float spec_blu
Definition: export_vrml.cpp:78
bool SetScale(const SGPOINT &aScale)
IFSG_TRANSFORM m_OutputPCB
defines the basic data associated with a single 3D model.
PAD_SHAPE_T GetShape() const
Function GetShape.
Definition: class_pad.h:202
#define abs(a)
Definition: auxiliary.h:84
EDA_TEXT_HJUSTIFY_T GetHorizJustify() const
Definition: eda_text.h:190
bool SetScale(double aWorldScale)
double m_layer_z[PCB_LAYER_ID_COUNT]
class EDGE_MODULE, a footprint edge
Definition: typeinfo.h:106
static void export_vrml_text_module(TEXTE_MODULE *module)
bool AddChildNode(SGNODE *aNode)
Function AddChildNode adds a node as a child owned by this node.
Definition: ifsg_node.cpp:249
double GetTextAngle() const
Definition: eda_text.h:164
Functions relatives to tracks, vias and segments used to fill zones.
bool AddIndex(int aIndex)
Function AddIndex adds a single index to the list.
Definition: ifsg_index.cpp:83
int GetThickness() const
Function GetThickness returns pen width.
Definition: eda_text.h:154
SGLIB_API bool WriteVRML(const char *filename, bool overwrite, SGNODE *aTopNode, bool reuse, bool renameNodes)
Function WriteVRML writes out the given node and its subnodes to a VRML2 file.
Definition: ifsg_api.cpp:81
This file contains miscellaneous commonly used macros and functions.
static void export_vrml_module(MODEL_VRML &aModel, BOARD *aPcb, MODULE *aModule, std::ostream *aOutputFile)
const wxPoint & GetArcStart() const
virtual wxString GetShownText() const
Returns the string actually shown after processing of the base text.
Definition: eda_text.h:135
static void build_quat(double x, double y, double z, double a, double q[4])
BOARD_ITEM * Next() const
static void export_vrml_circle(MODEL_VRML &aModel, LAYER_NUM layer, double startx, double starty, double endx, double endy, double width)
#define TO_UTF8(wxstring)
Macro TO_UTF8 converts a wxString to a UTF8 encoded C string for all wxWidgets build modes...
Definition: macros.h:47
bool AddNormal(double aXValue, double aYValue, double aZValue)
static void export_vrml_padshape(MODEL_VRML &aModel, VRML_LAYER *aTinLayer, D_PAD *aPad)
PROJECT & Prj() const
Function Prj returns a reference to the PROJECT "associated with" this KIWAY.
float ambient
Definition: export_vrml.cpp:84
float diffuse_grn
Definition: export_vrml.cpp:73
PCB_LAYER_ID
A quick note on layer IDs:
STROKE_T GetShape() const
VRML_LAYER m_bot_silk
Class LSET is a set of PCB_LAYER_IDs.
static void export_vrml_drawsegment(MODEL_VRML &aModel, DRAWSEGMENT *drawseg)
const wxPoint & GetEnd() const
Function GetEnd returns the ending point of the graphic.
Class IFSG_NORMALS is the wrapper for the SGNORMALS class.
Definition: ifsg_normals.h:40
VRML_LAYER m_top_silk
bool SetAmbient(float aRVal, float aGVal, float aBVal)
double GetOrientation() const
Definition: class_module.h:160
Class SHAPE_POLY_SET.
TEXTE_MODULE & Value()
read/write accessors:
Definition: class_module.h:462
const wxPoint & GetStart() const
Definition: class_track.h:121
const wxPoint & GetPosition() const override
Definition: class_pad.h:206
Arcs (with rounded ends)
LSET GetLayerSet() const override
Function GetLayerSet returns a "layer mask", which is a bitmap of all layers on which the TRACK segme...
Definition: class_pad.h:378
static void export_round_padstack(MODEL_VRML &aModel, BOARD *pcb, double x, double y, double r, LAYER_NUM bottom_layer, LAYER_NUM top_layer, double hole)
VRML_LAYER m_board
D_PAD * Next() const
Definition: class_pad.h:146
#define MIN_VRML_LINEWIDTH
Definition: export_vrml.cpp:53
static bool USE_RELPATH
Definition: export_vrml.cpp:63
static SGNODE * getSGColor(VRML_COLOR_INDEX colorIdx)
const wxSize & GetSize() const
Definition: class_pad.h:255
#define OPEN_OSTREAM(var, name)
BOARD_DESIGN_SETTINGS & GetDesignSettings() const
Function GetDesignSettings.
Definition: class_board.h:532
float spec_red
Definition: export_vrml.cpp:76
void GetPositionsOfLinesOfMultilineText(std::vector< wxPoint > &aPositions, int aLineCount) const
Function GetPositionsOfLinesOfMultilineText Populates aPositions with the position of each line of a ...
Definition: eda_text.cpp:327
bool SetRotation(const SGVECTOR &aRotationAxis, double aAngle)
const SHAPE_LINE_CHAIN & COutline(int aIndex) const
static void export_vrml_arc(MODEL_VRML &aModel, LAYER_NUM layer, double centerx, double centery, double arc_startx, double arc_starty, double width, double arc_angle)
static wxString SUBDIR_3D
Definition: export_vrml.cpp:67
static void export_vrml_pcbtext(MODEL_VRML &aModel, TEXTE_PCB *text)
int GetAreaCount() const
Function GetAreaCount.
Definition: class_board.h:1011
static void export_vrml_tracks(MODEL_VRML &aModel, BOARD *pcb)
static void export_vrml_board(MODEL_VRML &aModel, BOARD *aPcb)
static void export_vrml_drawings(MODEL_VRML &aModel, BOARD *pcb)
float spec_grn
Definition: export_vrml.cpp:77
const SHAPE_POLY_SET & GetFilledPolysList() const
Function GetFilledPolysList returns a reference to the list of filled polygons.
Definition: class_zone.h:600
VRML_LAYER m_bot_copper
Class LSEQ is a sequence (and therefore also a set) of PCB_LAYER_IDs.
void LayerPair(PCB_LAYER_ID *top_layer, PCB_LAYER_ID *bottom_layer) const
Function LayerPair Return the 2 layers used by the via (the via actually uses all layers between thes...
S3D_FILENAME_RESOLVER * GetResolver(void)
Definition: 3d_cache.cpp:739
int LAYER_NUM
Type LAYER_NUM can be replaced with int and removed.
LAYER_NUM m_text_layer
static void write_layers(MODEL_VRML &aModel, BOARD *aPcb, const char *aFileName, OSTREAM *aOutputFile)
float emit_grn
Definition: export_vrml.cpp:81
std::list< SGNODE * > m_components
static void export_vrml_edge_module(MODEL_VRML &aModel, EDGE_MODULE *aOutline, double aOrientation)
bool NewNode(SGNODE *aParent) override
Function NewNode creates a new node to associate with this wrapper.
static wxString PROJ_DIR
Definition: export_vrml.cpp:68
bool SetIndices(size_t nIndices, int *aIndexList)
Function SetIndices sets the number of indices and creates a copy of the given index data...
Definition: ifsg_index.cpp:63
class TEXTE_MODULE, text in a footprint
Definition: typeinfo.h:105
EDA_TEXT_VJUSTIFY_T GetVertJustify() const
Definition: eda_text.h:191
SGLIB_API SGVECTOR CalcTriNorm(const SGPOINT &p1, const SGPOINT &p2, const SGPOINT &p3)
Function CalcTriNorm returns the normal vector of a triangle described by vertices p1...
Definition: ifsg_api.cpp:606
bool SetSpecular(float aRVal, float aGVal, float aBVal)
static void export_vrml_zones(MODEL_VRML &aModel, BOARD *aPcb)
TRACK * Next() const
Definition: class_track.h:98
static const wxChar * GetChars(const wxString &s)
Function GetChars returns a wxChar* to the actual wxChar* data within a wxString, and is helpful for ...
Definition: macros.h:92
double GetAngle() const
see class PGM_BASE
bool SetCoordsList(size_t aListSize, const SGPOINT *aCoordsList)
ZONE_CONTAINER * GetArea(int index) const
Function GetArea returns the Area (Zone Container) at a given index.
Definition: class_board.h:982
bool ExportVRML_File(const wxString &aFullFileName, double aMMtoWRMLunit, bool aExport3DFiles, bool aUseRelativePaths, bool aUsePlainPCB, const wxString &a3D_Subdir, double aXRef, double aYRef)
Function ExportVRML_File Creates the file(s) exporting current BOARD to a VRML file.
float emit_blu
Definition: export_vrml.cpp:82
bool SetShininess(float aShininess)
double DEG2RAD(double deg)
Definition: trigo.h:191
int GetDrillValue() const
Function GetDrillValue "calculates" the drill value for vias (m-Drill if > 0, or default drill value ...
Class BOARD holds information pertinent to a Pcbnew printed circuit board.
Definition: class_board.h:169
wxString ResolvePath(const wxString &aFileName)
Function ResolvePath determines the full path of the given file name.
bool IsMirrored() const
Definition: eda_text.h:179
DLIST< MODULE > m_Modules
Definition: class_board.h:245
float diffuse_red
Definition: export_vrml.cpp:72
Class SHAPE_LINE_CHAIN.
bool IsVisible() const
Definition: eda_text.h:176
double m_arcMinLen
int GetWidth() const
Definition: class_track.h:115
Class IFSG_FACESET is the wrapper for the SGFACESET class.
Definition: ifsg_faceset.h:40
double m_arcMaxLen
static DIRECTION_45::AngleType angle(const VECTOR2I &a, const VECTOR2I &b)
bool NewNode(SGNODE *aParent) override
Function NewNode creates a new node to associate with this wrapper.
Class IFSG_TRANSFORM is the wrapper for the VRML compatible TRANSFORM block class SCENEGRAPH...
SGLIB_API void DestroyNode(SGNODE *aNode)
Function DestroyNode deletes the given SG* class node.
Definition: ifsg_api.cpp:210
double GetOrientation() const
Function GetOrientation returns the rotation angle of the pad in tenths of degrees, but soon degrees.
Definition: class_pad.h:358
static void create_vrml_shell(IFSG_TRANSFORM &PcbOutput, VRML_COLOR_INDEX colorID, VRML_LAYER *layer, double top_z, double bottom_z)
double DECIDEG2RAD(double deg)
Definition: trigo.h:195
static void from_quat(double q[4], double rot[4])
const wxSize & GetDelta() const
Definition: class_pad.h:258
defines the display data cache manager for 3D models
Class EDA_ITEM is a base class for most all the KiCad significant classes, used in schematics and boa...
Definition: base_struct.h:165
VTBL_ENTRY const wxString GetProjectPath() const
Function GetProjectPath returns the full path of the project.
Definition: project.cpp:102
int GetWidth() const
double m_brd_thickness
wxPoint ShapePos() const
Definition: class_pad.cpp:500
static const int PRECISION
Definition: export_vrml.cpp:66
static bool GetLayer(MODEL_VRML &aModel, LAYER_NUM layer, VRML_LAYER **vlayer)
double m_minLineWidth
static bool USE_DEFS
Definition: export_vrml.cpp:62
static void vrml_text_callback(int x0, int y0, int xf, int yf)
This file is part of the common libary.
DLIST< BOARD_ITEM > & GraphicalItemsList()
Definition: class_module.h:137
class VIA, a via (like a track segment on a copper layer)
Definition: typeinfo.h:108
#define PLATE_OFFSET
Definition: export_vrml.cpp:58
DLIST< D_PAD > & PadsList()
Definition: class_module.h:134
static void export_vrml_via(MODEL_VRML &aModel, BOARD *aPcb, const VIA *aVia)
void Destroy(void)
Function Destroy deletes the object held by this wrapper.
Definition: ifsg_node.cpp:54
DLIST< TRACK > m_Track
Definition: class_board.h:246
Module description (excepted pads)
Definition: colors.h:45
const wxSize & GetTextSize() const
Definition: eda_text.h:215
#define CLOSE_STREAM(var)
SCENEGRAPH * Load(const wxString &aModelFile)
Function Load attempts to load the scene data for a model; it will consult the internal cache list an...
Definition: 3d_cache.cpp:271
static void export_vrml_line(MODEL_VRML &aModel, LAYER_NUM layer, double startx, double starty, double endx, double endy, double width)
VRML_LAYER m_top_copper
double Distance(double x1, double y1, double x2, double y2)
VRML_LAYER m_top_tin
void SetFillMode(int aFillMode)
How to fill areas: 0 = use filled polygons, 1 => fill with segments.
Definition: class_zone.h:200
EDGE_MODULE class definition.
class DRAWSEGMENT, a segment not on copper layers
Definition: typeinfo.h:103
const wxPoint & GetStart() const
Function GetStart returns the starting point of the graphic.
const VECTOR2I & CPoint(int aIndex) const
Function CPoint()
VRML_COLOR & GetColor(VRML_COLOR_INDEX aIndex)
float emit_red
Definition: export_vrml.cpp:80
bool AddCoord(double aXValue, double aYValue, double aZValue)
float diffuse_blu
Definition: export_vrml.cpp:74
double GetLayerZ(LAYER_NUM aLayer)
static VRML_COLOR colors[VRML_COLOR_LAST]
DLIST_ITERATOR_WRAPPER< BOARD_ITEM > Drawings()
Definition: class_board.h:251
const wxPoint & GetPosition() const override
#define ART_OFFSET
Definition: export_vrml.cpp:56
Class IFSG_SHAPE is the wrapper for the SGSHAPE class.
Definition: ifsg_shape.h:40
#define min(a, b)
Definition: auxiliary.h:85
bool NewNode(SGNODE *aParent) override
Function NewNode creates a new node to associate with this wrapper.
VRML_COLOR(float dr, float dg, float db, float sr, float sg, float sb, float er, float eg, float eb, float am, float tr, float sh)
Class COLOR4D is the color representation with 4 components: red, green, blue, alpha.
Definition: color4d.h:39