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