32 #include <wx/msgdlg.h> 48 #include "vrml_layer.h" 58 #define ERR_APPROX_MAX_MM 0.005 62 m_OutputPCB( nullptr )
84 0.12f, 0.20f, 0.19f, 0.01f, 0.03f, 0.01f, 0.0f, 0.0f, 0.0f, 0.8f, 0.0f, 0.02f );
87 0.72f, 0.45f, 0.2f, 0.01f, 0.05f, 0.01f, 0.0f, 0.0f, 0.0f, 0.8f, 0.0f, 0.02f );
90 0.7f, 0.7f, 0.9f, 0.1f, 0.1f, 0.1f, 0.0f, 0.0f, 0.0f, 0.9f, 0.0f, 0.02f );
93 0.0f, 0.0f, 0.8f, 0.0f, 0.8f );
96 0.07f, 0.3f, 0.12f, 0.01f, 0.03f, 0.01f, 0.0f, 0.0f, 0.0f, 0.8f, 0.25f, 0.02f );
132 if( aWorldScale < 0.001 || aWorldScale > 10.0 )
133 throw( std::runtime_error(
"WorldScale out of range (valid range is 0.001 to 10.0)" ) );
147 m_holes.SetVertexOffsets( aXoff, aYoff );
175 default:
return false;
188 for(
int lcnt = 0; lcnt < 2; lcnt++ )
214 VRML_LAYER* vrmllayer[] =
220 for(
int lcnt = 0; ; lcnt++ )
222 if( vrmllayer[lcnt] ==
nullptr )
238 VRML_LAYER* aLayer,
bool aPlane,
bool aTop,
239 double aTop_z,
double aBottom_z )
242 static const char* shape_boiler[] =
249 " appearance Appearance {\n",
250 " material Material {\n",
254 " geometry IndexedFaceSet {\n",
256 " coord Coordinate {\n",
273 int marker_found = 0, lineno = 0;
275 while( marker_found < 4 )
277 if( shape_boiler[lineno] )
279 aOut_file << shape_boiler[lineno];
285 switch( marker_found )
289 std::streamsize lastPrecision = aOut_file.precision();
290 aOut_file <<
" diffuseColor " << std::setprecision(3);
295 aOut_file <<
" specularColor ";
296 aOut_file << aColor.
spec_red <<
" ";
297 aOut_file << aColor.
spec_grn <<
" ";
298 aOut_file << aColor.
spec_blu <<
"\n";
300 aOut_file <<
" emissiveColor ";
301 aOut_file << aColor.
emit_red <<
" ";
302 aOut_file << aColor.
emit_grn <<
" ";
303 aOut_file << aColor.
emit_blu <<
"\n";
305 aOut_file <<
" ambientIntensity " << aColor.
ambient <<
"\n";
306 aOut_file <<
" transparency " << aColor.
transp <<
"\n";
307 aOut_file <<
" shininess " << aColor.
shiny <<
"\n";
308 aOut_file.precision( lastPrecision );
315 aLayer->WriteVertices( aTop_z, aOut_file,
m_precision );
317 aLayer->Write3DVertices( aTop_z, aBottom_z, aOut_file,
m_precision );
325 aLayer->WriteIndices( aTop, aOut_file );
327 aLayer->Write3DIndices( aOut_file );
530 if( i < copper_layers )
558 for(
int icnt = 0; icnt < aOutlines.
OutlineCount(); icnt++ )
562 int seg = aVlayer->NewContour();
564 for(
int jj = 0; jj < outline.
PointCount(); jj++ )
568 throw( std::runtime_error( aVlayer->GetError() ) );
571 aVlayer->EnsureWinding( seg,
false );
580 wxLogWarning(
_(
"Board outline is malformed. Run DRC for a full analysis." ) );
591 for(
int j = 0; j < outline.
PointCount(); j++ )
609 wxLogError(
_(
"VRML Export Failed: Could not add holes to contours." ) );
619 m_holes.EnsureWinding( seg,
true );
634 const PCB_VIA*
via = static_cast<const PCB_VIA*>( track );
636 via->LayerPair( &top_layer, &bottom_layer );
639 if( top_layer !=
F_Cu && bottom_layer !=
B_Cu )
645 if( hole_radius <= 0 )
661 double minSegLength = M_PI * 2.0 * hole_radius / nsides;
662 double maxSegLength = minSegLength*2.0;
664 m_holes.SetArcParams( nsides*2, minSegLength, maxSegLength );
665 m_plated_holes.SetArcParams( nsides*2, minSegLength, maxSegLength );
667 m_holes.AddCircle( x, -y, hole_radius,
true,
true );
680 double hole_drill = std::min( hole_drill_w, hole_drill_h );
694 double minSegLength = M_PI * hole_drill / nsides;
695 double maxSegLength = minSegLength*2.0;
697 m_holes.SetArcParams( nsides*2, minSegLength, maxSegLength );
698 m_plated_holes.SetArcParams( nsides*2, minSegLength, maxSegLength );
716 hole_drill_w * 2.0, hole_drill_h * 2.0,
721 m_holes.AddSlot( hole_x, -hole_y, hole_drill_w * 2.0, hole_drill_h * 2.0,
732 m_plated_holes.AddCircle( hole_x, -hole_y, hole_drill,
true,
false );
736 m_holes.AddCircle( hole_x, -hole_y, hole_drill,
true,
false );
748 static void build_quat(
double x,
double y,
double z,
double a,
double q[4] )
750 double sina = sin( a / 2 );
762 rot[3] = acos( q[3] ) * 2;
764 for(
int i = 0; i < 3; i++ )
765 rot[i] = q[i] / sin( rot[3] / 2 );
774 tmp[0] = q2[3] * q1[0] + q2[0] * q1[3] + q2[1] * q1[2] - q2[2] * q1[1];
775 tmp[1] = q2[3] * q1[1] + q2[1] * q1[3] + q2[2] * q1[0] - q2[0] * q1[2];
776 tmp[2] = q2[3] * q1[2] + q2[2] * q1[3] + q2[0] * q1[1] - q2[1] * q1[0];
777 tmp[3] = q2[3] * q1[3] - q2[0] * q1[0] - q2[1] * q1[1] - q2[2] * q1[2];
793 wxCHECK( aFootprint, );
802 auto sM = aFootprint->
Models().begin();
803 auto eM = aFootprint->
Models().end();
817 if(
nullptr == mod3d )
828 double rotx = -sM->m_Rotation.x;
829 double roty = -sM->m_Rotation.y;
830 double rotz = -sM->m_Rotation.z;
840 double q1[4], q2[4], rot[4];
853 double offsetFactor = 1000.0f *
IU_PER_MILS / 25.4f;
857 double offsetx = sM->m_Offset.x * offsetFactor;
858 double offsety = sM->m_Offset.y * offsetFactor;
859 double offsetz = sM->m_Offset.z * offsetFactor;
875 wxCHECK( aOutputFile, );
877 int old_precision = aOutputFile->precision();
883 dstFile.SetName( srcFile.GetName() );
884 dstFile.SetExt( wxT(
"wrl" ) );
887 wxDateTime srcModTime = srcFile.GetModificationTime();
888 wxDateTime destModTime = srcModTime;
890 destModTime.SetToCurrent();
892 if( dstFile.FileExists() )
893 destModTime = dstFile.GetModificationTime();
895 if( srcModTime != destModTime )
897 wxString fileExt = srcFile.GetExt();
902 if( fileExt == wxT(
"wrl" ) )
904 if( !wxCopyFile( srcFile.GetFullPath(), dstFile.GetFullPath() ) )
915 (*aOutputFile) <<
"Transform {\n";
918 if( std::abs( rot[3] ) > 0.0001745 )
920 (*aOutputFile) <<
" rotation ";
921 (*aOutputFile) << rot[0] <<
" " << rot[1] <<
" " << rot[2] <<
" " << rot[3] <<
"\n";
924 (*aOutputFile) <<
" translation ";
925 (*aOutputFile) << trans.x <<
" ";
926 (*aOutputFile) << trans.y <<
" ";
927 (*aOutputFile) << trans.z <<
"\n";
929 (*aOutputFile) <<
" scale ";
930 (*aOutputFile) << sM->m_Scale.x <<
" ";
931 (*aOutputFile) << sM->m_Scale.y <<
" ";
932 (*aOutputFile) << sM->m_Scale.z <<
"\n";
934 (*aOutputFile) <<
" children [\n Inline {\n url \"";
938 wxFileName tmp = dstFile;
939 tmp.SetExt( wxEmptyString );
940 tmp.SetName( wxEmptyString );
942 dstFile.MakeRelativeTo( tmp.GetPath() );
945 wxString fn = dstFile.GetFullPath();
946 fn.Replace( wxT(
"\\" ), wxT(
"/" ) );
947 (*aOutputFile) <<
TO_UTF8( fn ) <<
"\"\n } ]\n";
948 (*aOutputFile) <<
" }\n";
950 aOutputFile->precision( old_precision );
957 if( std::abs( rot[3] ) > 0.0001745 )
961 modelShape->
SetScale(
SGPOINT( sM->m_Scale.x, sM->m_Scale.y, sM->m_Scale.z ) );
981 bool aExport3DFiles,
bool aUseRelativePaths,
982 const wxString& a3D_Subdir,
983 double aXRef,
double aYRef )
1000 model3d.
SetOffset( -aXRef / 2.54, aYRef / 2.54 );
1023 model3d.ExportVrmlDrawings();
1026 model3d.ExportVrmlTracks();
1029 model3d.ExportVrmlZones();
1047 catch(
const std::exception& e )
1050 msg <<
_(
"IDF Export Failed:\n" ) <<
FROM_UTF8( e.what() );
1051 wxMessageBox( msg );
1064 if( ! subdir.DirExists() )
1066 if( !wxDir::Make( subdir.GetFullPath() ) )
1067 throw( std::runtime_error(
"Could not create 3D model subdirectory" ) );
1072 if( output_file.fail() )
1074 std::ostringstream ostr;
1075 ostr <<
"Could not open file '" <<
TO_UTF8( aFullFileName ) <<
"'";
1076 throw( std::runtime_error( ostr.str().c_str() ) );
1079 output_file.imbue( std::locale::classic() );
1082 wxString fn = aFullFileName;
1083 fn.Replace( wxT(
"\\" ) , wxT(
"/" ) );
1084 output_file <<
"#VRML V2.0 utf8\n";
1085 output_file <<
"WorldInfo {\n";
1086 output_file <<
" title \"" <<
TO_UTF8( fn ) <<
" - Generated by Pcbnew\"\n";
1087 output_file <<
"}\n";
1088 output_file <<
"Transform {\n";
1089 output_file <<
" scale " << std::setprecision(
m_precision );
1093 output_file <<
" children [\n";
1103 output_file <<
"]\n}\n";
1110 if( colorIdx == -1 )
1136 VRML_LAYER* layer,
double top_z,
bool aTopPlane )
1138 std::vector< double > vertices;
1139 std::vector< int > idxPlane;
1141 if( !( *layer ).Get2DTriangles( vertices, idxPlane, top_z, aTopPlane ) )
1146 if( ( idxPlane.size() % 3 ) )
1148 throw( std::runtime_error(
"[BUG] index lists are not a multiple of 3 (not a triangle " 1152 std::vector< SGPOINT > vlist;
1153 size_t nvert = vertices.size() / 3;
1156 for(
size_t i = 0; i < nvert; ++i, j+= 3 )
1157 vlist.emplace_back( vertices[j], vertices[j+1], vertices[j+2] );
1166 coordIdx.
SetIndices( idxPlane.size(), &idxPlane[0] );
1172 for(
size_t i = 0; i < nvert; ++i )
1177 for(
size_t i = 0; i < nvert; ++i )
1184 if(
nullptr != modelColor )
1187 shape.AddChildNode( modelColor );
1189 shape.AddRefNode( modelColor );
1195 VRML_LAYER* layer,
double top_z,
double bottom_z )
1197 std::vector< double > vertices;
1198 std::vector< int > idxPlane;
1199 std::vector< int > idxSide;
1201 if( top_z < bottom_z )
1208 if( !( *layer ).Get3DTriangles( vertices, idxPlane, idxSide, top_z, bottom_z )
1209 || idxPlane.empty() || idxSide.empty() )
1214 if( ( idxPlane.size() % 3 ) || ( idxSide.size() % 3 ) )
1216 throw( std::runtime_error(
"[BUG] index lists are not a multiple of 3 (not a " 1217 "triangle list)" ) );
1220 std::vector< SGPOINT > vlist;
1221 size_t nvert = vertices.size() / 3;
1224 for(
size_t i = 0; i < nvert; ++i, j+= 3 )
1225 vlist.emplace_back( vertices[j], vertices[j+1], vertices[j+2] );
1234 coordIdx.
SetIndices( idxPlane.size(), &idxPlane[0] );
1241 for(
size_t i = 0; i < j; ++i )
1245 for(
size_t i = 0; i < j; ++i )
1251 if(
nullptr != modelColor )
1254 shape.AddChildNode( modelColor );
1256 shape.AddRefNode( modelColor );
1261 shape.NewNode( tx0 );
1262 shape.AddRefNode( modelColor );
1269 std::vector< int >::iterator sI = idxSide.begin();
1270 std::vector< int >::iterator eI = idxSide.end();
static LSET AllCuMask(int aCuLayerCount=MAX_CU_LAYERS)
Return a mask holding the requested number of Cu PCB_LAYER_IDs.
void ExportVrmlFootprint(FOOTPRINT *aFootprint, std::ostream *aOutputFile)
IFSG_TRANSFORM m_OutputPCB
VRML_LAYER m_plated_holes
double GetLayerZ(LAYER_NUM aLayer)
int OutlineCount() const
Return the number of vertices in a given outline/hole.
bool NewNode(SGNODE *aParent) override
Function NewNode creates a new node to associate with this wrapper.
static wxString FROM_UTF8(const char *cstring)
Convert a UTF8 encoded C string to a wxString for all wxWidgets build modes.
bool GetBoardPolygonOutlines(SHAPE_POLY_SET &aOutlines, OUTLINE_ERROR_HANDLER *aErrorHandler=nullptr)
Extract the board outlines and build a closed polygon from lines, arcs and circle items on edge cut l...
static void compose_quat(double q1[4], double q2[4], double qr[4])
std::list< SGNODE * > m_components
IFSG_COORDS is the wrapper for SGCOORDS.
void ExportVrmlPadHole(PAD *aPad)
IFSG_COORDINDEX is the wrapper for SGCOORDINDEX.
void ConvertBrdLayerToPolygonalContours(PCB_LAYER_ID aLayer, SHAPE_POLY_SET &aOutlines) const
Build a set of polygons which are the outlines of copper items (pads, tracks, vias,...
bool SetTransparency(float aTransparency) noexcept
VRML_COLOR vrml_colors_list[VRML_COLOR_LAST]
bool SetDiffuse(float aRVal, float aGVal, float aBVal)
void SetLayerZ(LAYER_NUM aLayer, double aValue)
bool AddRefNode(SGNODE *aNode)
Function AddRefNode adds a reference to an existing node which is not owned by (not a child of) this ...
void SetVector(double aXVal, double aYVal, double aZVal)
SHAPE_LINE_CHAIN & Hole(int aOutline, int aHole)
Return the aIndex-th subpolygon in the set.
int GetBoardThickness() const
int LAYER_NUM
This can be replaced with int and removed.
void ExportVrmlViaHoles()
SGLIB_API SGNODE * GetSGNodeParent(SGNODE *aNode)
SGNODE * getSGColor(VRML_COLOR_INDEX colorIdx)
bool SetParent(SGNODE *aParent)
Function SetParent sets the parent SGNODE of this object.
bool ExportVRML_File(const wxString &aFullFileName, double aMMtoWRMLunit, bool aExport3DFiles, bool aUseRelativePaths, const wxString &a3D_Subdir, double aXRef, double aYRef)
Create the file(s) exporting current BOARD to a VRML file.
void RotatePoint(int *pX, int *pY, double angle)
The base class of all Scene Graph nodes.
collects header files for all SG* wrappers and the API
defines the basic data associated with a single 3D model.
SGNODE * GetRawPtr(void) noexcept
Function GetRawPtr() returns the raw internal SGNODE pointer.
int PointCount() const
Return the number of points (vertices) in this line chain.
BOARD_DESIGN_SETTINGS & GetDesignSettings() const
bool AddChildNode(SGNODE *aNode)
Function AddChildNode adds a node as a child owned by this node.
void ExportFp3DModelsAsLinkedFile(const wxString &aFullFileName)
VRML_LAYER m_bot_soldermask
bool AddIndex(int aIndex)
Function AddIndex adds a single index to the list.
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.
This file contains miscellaneous commonly used macros and functions.
void write_triangle_bag(std::ostream &aOut_file, const VRML_COLOR &aColor, VRML_LAYER *aLayer, bool aPlane, bool aTop, double aTop_z, double aBottom_z)
void writeLayers(const char *aFileName, OSTREAM *aOutputFile)
static void build_quat(double x, double y, double z, double a, double q[4])
#define TO_UTF8(wxstring)
Convert a wxString to a UTF8 encoded C string for all wxWidgets build modes.
bool AddNormal(double aXValue, double aYValue, double aZValue)
const VECTOR2I & CPoint(int aIndex) const
Return a reference to a given point in the line chain.
const wxSize & GetDrillSize() const
like PAD_PTH, but not plated
wxString m_Subdir3DFpModels
SGLIB_API void DestroyNode(SGNODE *aNode) noexcept
Function DestroyNode deletes the given SG* class node.
IFSG_NORMALS is the wrapper for the SGNORMALS class.
bool SetAmbient(float aRVal, float aGVal, float aBVal)
double GetOrientation() const
Return the rotation angle of the pad in a variety of units (the basic call returns tenths of degrees)...
bool m_UseRelPathIn3DModelFilename
Represent a set of closed polygons.
PROJECT & Prj() const
Return a reference to the PROJECT associated with this KIWAY.
void ComputeLayer3D_Zpos()
FOOTPRINTS & Footprints()
VRML_LAYER m_top_soldermask
VRML_COLOR & GetColor(VRML_COLOR_INDEX aIndex)
#define OPEN_OSTREAM(var, name)
bool GetLayer3D(LAYER_NUM layer, VRML_LAYER **vlayer)
constexpr std::size_t arrayDim(T const (&)[N]) noexcept
Returns # of elements in an array.
void create_vrml_shell(IFSG_TRANSFORM &PcbOutput, VRML_COLOR_INDEX colorID, VRML_LAYER *layer, double top_z, double bottom_z)
a few functions useful in geometry calculations.
void create_vrml_plane(IFSG_TRANSFORM &PcbOutput, VRML_COLOR_INDEX colorID, VRML_LAYER *layer, double aHeight, bool aTopPlane)
SGNODE * m_sgmaterial[VRML_COLOR_LAST]
bool SetShininess(float aShininess) noexcept
int HoleCount(int aOutline) const
Return the reference to aIndex-th outline in the set.
void Fracture(POLYGON_MODE aFastMode)
Convert a single outline slitted ("fractured") polygon into a set ouf outlines with holes.
LSEQ is a sequence (and therefore also a set) of PCB_LAYER_IDs.
static EXPORTER_PCB_VRML * model_vrml
void ExportVrmlSolderMask()
bool NewNode(SGNODE *aParent) override
Function NewNode creates a new node to associate with this wrapper.
wxString ResolvePath(const wxString &aFileName)
Determines the full path of the given file name.
bool SetIndices(size_t nIndices, int *aIndexList)
Function SetIndices sets the number of indices and creates a copy of the given index data.
bool SetScale(double aWorldScale)
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,...
SHAPE_POLY_SET m_pcbOutlines
bool SetSpecular(float aRVal, float aGVal, float aBVal)
bool SetCoordsList(size_t aListSize, const SGPOINT *aCoordsList)
double DEG2RAD(double deg)
wxPoint GetPosition() const override
PAD_DRILL_SHAPE_T GetDrillShape() const
Information pertinent to a Pcbnew printed circuit board.
Represent a polyline containing arcs as well as line segments: A chain of connected line and/or arc s...
PCB_LAYER_ID
A quick note on layer IDs:
PAD_ATTRIB GetAttribute() const
const SHAPE_LINE_CHAIN & COutline(int aIndex) const
IFSG_FACESET is the wrapper for the SGFACESET class.
FILENAME_RESOLVER * GetResolver() noexcept
bool NewNode(SGNODE *aParent) override
Function NewNode creates a new node to associate with this wrapper.
int GetCopperLayerCount() const
double DECIDEG2RAD(double deg)
static void from_quat(double q[4], double rot[4])
S3D_CACHE * m_Cache3Dmodels
#define ERR_APPROX_MAX_MM
void SetOffset(double aXoff, double aYoff)
class PCB_VIA, a via (like a track segment on a copper layer)
void Destroy(void)
Function Destroy deletes the object held by this wrapper.
void BooleanSubtract(const SHAPE_POLY_SET &b, POLYGON_MODE aFastMode)
Perform boolean polyset intersection For aFastMode meaning, see function booleanOp.
#define CLOSE_STREAM(var)
SCENEGRAPH * Load(const wxString &aModelFile)
Attempt to load the scene data for a model.
void ExportStandardLayers()
double m_BoardToVrmlScale
static constexpr int Millimeter2iu(double mm)
virtual PCB_LAYER_ID GetLayer() const
Return the primary layer this item is on.
int GetArcToSegmentCount(int aRadius, int aErrorMax, double aArcAngleDegree)
bool AddCoord(double aXValue, double aYValue, double aZValue)
bool m_UseInlineModelsInBrdfile
void ExportVrmlPolygonSet(VRML_LAYER *aVlayer, const SHAPE_POLY_SET &aOutlines)
IFSG_SHAPE is the wrapper for the SGSHAPE class.
bool NewNode(SGNODE *aParent) override
Function NewNode creates a new node to associate with this wrapper.
double m_layer_z[PCB_LAYER_ID_COUNT]