From 1459f8bfb16f9cd4e135652d88c3f873848c1fce Mon Sep 17 00:00:00 2001 From: unknown Date: Mon, 16 Jun 2014 14:02:15 +0200 Subject: [PATCH] Apply vrml_layer_pth, from Cirilo Bernardo --- pcbnew/exporters/export_vrml.cpp | 142 ++++++------ utils/idftools/vrml_layer.cpp | 358 ++++++++++++++++++++++++------- utils/idftools/vrml_layer.h | 51 ++++- 3 files changed, 396 insertions(+), 155 deletions(-) diff --git a/pcbnew/exporters/export_vrml.cpp b/pcbnew/exporters/export_vrml.cpp index 5b8de962d1..4da01357c9 100644 --- a/pcbnew/exporters/export_vrml.cpp +++ b/pcbnew/exporters/export_vrml.cpp @@ -25,37 +25,6 @@ */ -/* - * NOTE: - * 1. for improved looks, create a DRILL layer for PTH drills. - * To render the improved board, render the vertical outline only - * for the board (no added drill holes), then render the - * outline only for PTH, and finally render the top and bottom - * of the board. NOTE: if we don't want extra eye-candy then - * we must maintain the current board export. - * Additional bits needed for improved eyecandy: - * + CalcOutline: calculates only the outline of a VRML_LAYER or - * a VERTICAL_HOLES - * + WriteVerticalIndices: writes the indices of only the vertical - * facets of a VRML_LAYER or a VRML_HOLES. - * + WriteVerticalVertices: writes only the outline vertices to - * form vertical walls; applies to VRML_LAYER and VRML_HOLES - * - * 2. How can we suppress fiducials such as those in the corners of the pic-programmer demo? - * - */ - -/* - * KNOWN BUGS: - * 1. silk outlines are sometimes mangled; this is somehow due to - * many overlapping segments. This does not happen in 3Dviewer - * so it is worth inspecting that code to see what is different. - * - * These artefacts can be suppressed for exploratory purposes by - * removing the line width parameter from the length calculation in - * export_vrml_line() - */ - #include #include #include @@ -88,7 +57,7 @@ #define MIN_VRML_LINEWIDTH 0.12 // offset for art layers, mm (silk, paste, etc) -#define ART_OFFSET 0.02 +#define ART_OFFSET 0.025 /* helper function: * some characters cannot be used in names, @@ -183,6 +152,7 @@ public: VRML_LAYER bot_silk; VRML_LAYER top_tin; VRML_LAYER bot_tin; + VRML_LAYER plated_holes; double scale; // board internal units to output scaling double minLineWidth; // minimum width of a VRML line segment @@ -229,8 +199,18 @@ public: void SetOffset( double aXoff, double aYoff ) { - tx = aXoff; - ty = aYoff; + tx = aXoff; + ty = -aYoff; + + holes.SetVertexOffsets( aXoff, aYoff ); + board.SetVertexOffsets( aXoff, aYoff ); + top_copper.SetVertexOffsets( aXoff, aYoff ); + bot_copper.SetVertexOffsets( aXoff, aYoff ); + top_silk.SetVertexOffsets( aXoff, aYoff ); + bot_silk.SetVertexOffsets( aXoff, aYoff ); + top_tin.SetVertexOffsets( aXoff, aYoff ); + bot_tin.SetVertexOffsets( aXoff, aYoff ); + plated_holes.SetVertexOffsets( aXoff, aYoff ); } double GetLayerZ( LAYER_NUM aLayer ) @@ -278,6 +258,7 @@ public: bot_silk.SetArcParams( iMaxSeg, smin, smax ); top_tin.SetArcParams( iMaxSeg, smin, smax ); bot_tin.SetArcParams( iMaxSeg, smin, smax ); + plated_holes.SetArcParams( iMaxSeg, smin, smax ); return true; } @@ -455,6 +436,16 @@ static void write_layers( MODEL_VRML& aModel, std::ofstream& output_file, BOARD* - Millimeter2iu( ART_OFFSET / 2.0 ) * aModel.scale, 0, aModel.precision ); + // VRML_LAYER PTH; + aModel.plated_holes.Tesselate( NULL, true ); + write_triangle_bag( output_file, aModel.GetColor( VRML_COLOR_TIN ), + &aModel.plated_holes, false, false, + aModel.GetLayerZ( LAST_COPPER_LAYER ) + + Millimeter2iu( ART_OFFSET / 2.0 ) * aModel.scale, + aModel.GetLayerZ( FIRST_COPPER_LAYER ) + - Millimeter2iu( ART_OFFSET / 2.0 ) * aModel.scale, + aModel.precision ); + // VRML_LAYER top_silk; aModel.top_silk.Tesselate( &aModel.holes ); write_triangle_bag( output_file, aModel.GetColor( VRML_COLOR_SILK ), @@ -588,10 +579,10 @@ static void export_vrml_drawsegment( MODEL_VRML& aModel, DRAWSEGMENT* drawseg ) { LAYER_NUM layer = drawseg->GetLayer(); double w = drawseg->GetWidth() * aModel.scale; - double x = drawseg->GetStart().x * aModel.scale + aModel.tx; - double y = drawseg->GetStart().y * aModel.scale + aModel.ty; - double xf = drawseg->GetEnd().x * aModel.scale + aModel.tx; - double yf = drawseg->GetEnd().y * aModel.scale + aModel.ty; + double x = drawseg->GetStart().x * aModel.scale; + double y = drawseg->GetStart().y * aModel.scale; + double xf = drawseg->GetEnd().x * aModel.scale; + double yf = drawseg->GetEnd().y * aModel.scale; // Items on the edge layer are handled elsewhere; just return if( layer == EDGE_N ) @@ -626,12 +617,10 @@ static void vrml_text_callback( int x0, int y0, int xf, int yf ) LAYER_NUM s_text_layer = model_vrml->s_text_layer; int s_text_width = model_vrml->s_text_width; double scale = model_vrml->scale; - double tx = model_vrml->tx; - double ty = model_vrml->ty; export_vrml_line( *model_vrml, s_text_layer, - x0 * scale + tx, y0 * scale + ty, - xf * scale + tx, yf * scale + ty, + x0 * scale, y0 * scale, + xf * scale, yf * scale, s_text_width * scale ); } @@ -729,8 +718,6 @@ static void export_vrml_board( MODEL_VRML& aModel, BOARD* pcb ) } double scale = aModel.scale; - double dx = aModel.tx; - double dy = aModel.ty; int i = 0; int seg; @@ -756,8 +743,8 @@ static void export_vrml_board( MODEL_VRML& aModel, BOARD* pcb ) if( bufferPcbOutlines[i].end_contour ) break; - aModel.board.AddVertex( seg, bufferPcbOutlines[i].x * scale + dx, - -(bufferPcbOutlines[i].y * scale + dy) ); + aModel.board.AddVertex( seg, bufferPcbOutlines[i].x * scale, + -(bufferPcbOutlines[i].y * scale ) ); ++i; } @@ -788,8 +775,8 @@ static void export_vrml_board( MODEL_VRML& aModel, BOARD* pcb ) if( allLayerHoles[i].end_contour ) break; - aModel.holes.AddVertex( seg, allLayerHoles[i].x * scale + dx, - -(allLayerHoles[i].y * scale + dy) ); + aModel.holes.AddVertex( seg, allLayerHoles[i].x * scale, + -(allLayerHoles[i].y * scale ) ); ++i; } @@ -849,8 +836,8 @@ static void export_vrml_via( MODEL_VRML& aModel, BOARD* pcb, const VIA* via ) hole = via->GetDrillValue() * aModel.scale / 2.0; r = via->GetWidth() * aModel.scale / 2.0; - x = via->GetStart().x * aModel.scale + aModel.tx; - y = via->GetStart().y * aModel.scale + aModel.ty; + x = via->GetStart().x * aModel.scale; + y = via->GetStart().y * aModel.scale; via->LayerPair( &top_layer, &bottom_layer ); // do not render a buried via @@ -873,10 +860,10 @@ static void export_vrml_tracks( MODEL_VRML& aModel, BOARD* pcb ) else if( track->GetLayer() == FIRST_COPPER_LAYER || track->GetLayer() == LAST_COPPER_LAYER ) export_vrml_line( aModel, track->GetLayer(), - track->GetStart().x * aModel.scale + aModel.tx, - track->GetStart().y * aModel.scale + aModel.ty, - track->GetEnd().x * aModel.scale + aModel.tx, - track->GetEnd().y * aModel.scale + aModel.ty, + track->GetStart().x * aModel.scale, + track->GetStart().y * aModel.scale, + track->GetEnd().x * aModel.scale, + track->GetEnd().y * aModel.scale, track->GetWidth() * aModel.scale ); } } @@ -886,9 +873,6 @@ static void export_vrml_zones( MODEL_VRML& aModel, BOARD* aPcb ) { double scale = aModel.scale; - double dx = aModel.tx; - double dy = aModel.ty; - double x, y; for( int ii = 0; ii < aPcb->GetAreaCount(); ii++ ) @@ -920,8 +904,8 @@ static void export_vrml_zones( MODEL_VRML& aModel, BOARD* aPcb ) while( i < nvert ) { - x = poly.GetX(i) * scale + dx; - y = -(poly.GetY(i) * scale + dy); + x = poly.GetX(i) * scale; + y = -(poly.GetY(i) * scale); if( poly.IsEndContour(i) ) break; @@ -971,10 +955,10 @@ static void export_vrml_edge_module( MODEL_VRML& aModel, EDGE_MODULE* aOutline, double aOrientation ) { LAYER_NUM layer = aOutline->GetLayer(); - double x = aOutline->GetStart().x * aModel.scale + aModel.tx; - double y = aOutline->GetStart().y * aModel.scale + aModel.ty; - double xf = aOutline->GetEnd().x * aModel.scale + aModel.tx; - double yf = aOutline->GetEnd().y * aModel.scale + aModel.ty; + double x = aOutline->GetStart().x * aModel.scale; + double y = aOutline->GetStart().y * aModel.scale; + double xf = aOutline->GetEnd().x * aModel.scale; + double yf = aOutline->GetEnd().y * aModel.scale; double w = aOutline->GetWidth() * aModel.scale; switch( aOutline->GetShape() ) @@ -1015,8 +999,8 @@ static void export_vrml_edge_module( MODEL_VRML& aModel, EDGE_MODULE* aOutline, corner.x += aOutline->GetPosition().x; corner.y += aOutline->GetPosition().y; - x = corner.x * aModel.scale + aModel.tx; - y = - ( corner.y * aModel.scale + aModel.ty ); + x = corner.x * aModel.scale; + y = - ( corner.y * aModel.scale ); if( !vl->AddVertex( seg, x, y ) ) throw( std::runtime_error( vl->GetError() ) ); @@ -1037,8 +1021,8 @@ static void export_vrml_padshape( MODEL_VRML& aModel, VRML_LAYER* aTinLayer, D_P { // The (maybe offset) pad position wxPoint pad_pos = aPad->ShapePos(); - double pad_x = pad_pos.x * aModel.scale + aModel.tx; - double pad_y = pad_pos.y * aModel.scale + aModel.ty; + double pad_x = pad_pos.x * aModel.scale; + double pad_y = pad_pos.y * aModel.scale; wxSize pad_delta = aPad->GetDelta(); double pad_dx = pad_delta.x * aModel.scale / 2.0; @@ -1121,22 +1105,36 @@ static void export_vrml_pad( MODEL_VRML& aModel, BOARD* pcb, D_PAD* aPad ) double hole_drill_w = (double) aPad->GetDrillSize().x * aModel.scale / 2.0; double hole_drill_h = (double) aPad->GetDrillSize().y * aModel.scale / 2.0; double hole_drill = std::min( hole_drill_w, hole_drill_h ); - double hole_x = aPad->GetPosition().x * aModel.scale + aModel.tx; - double hole_y = aPad->GetPosition().y * aModel.scale + aModel.ty; + double hole_x = aPad->GetPosition().x * aModel.scale; + double hole_y = aPad->GetPosition().y * aModel.scale; // Export the hole on the edge layer if( hole_drill > 0 ) { + bool pth = false; + + if( aPad->GetAttribute() != PAD_HOLE_NOT_PLATED ) + pth = true; + if( aPad->GetDrillShape() == PAD_DRILL_OBLONG ) { // Oblong hole (slot) aModel.holes.AddSlot( hole_x, -hole_y, hole_drill_w * 2.0, hole_drill_h * 2.0, - aPad->GetOrientation()/10.0, true ); + aPad->GetOrientation()/10.0, true, pth ); + + if( pth ) + aModel.plated_holes.AddSlot( hole_x, -hole_y, + hole_drill_w * 2.0, hole_drill_h * 2.0, + aPad->GetOrientation()/10.0, true, false ); } else { // Drill a round hole - aModel.holes.AddCircle( hole_x, -hole_y, hole_drill, true ); + aModel.holes.AddCircle( hole_x, -hole_y, hole_drill, true, pth ); + + if( pth ) + aModel.plated_holes.AddCircle( hole_x, -hole_y, hole_drill, true, false ); + } } @@ -1390,7 +1388,7 @@ bool PCB_EDIT_FRAME::ExportVRML_File( const wxString& aFullFileName, EDA_RECT bbbox = pcb->ComputeBoundingBox(); model3d.SetOffset( -model3d.scale * bbbox.Centre().x, - -model3d.scale * bbbox.Centre().y ); + model3d.scale * bbbox.Centre().y ); output_file << " children [\n"; diff --git a/utils/idftools/vrml_layer.cpp b/utils/idftools/vrml_layer.cpp index 32ed105210..f8405afb10 100644 --- a/utils/idftools/vrml_layer.cpp +++ b/utils/idftools/vrml_layer.cpp @@ -23,6 +23,14 @@ * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA */ +// Wishlist: +// 1. crop anything outside the board outline on PTH, silk, and copper layers +// 2. on the PTH layer, handle cropped holes differently from others; +// these are assumed to be castellated edges and the profile is not +// a closed loop as assumed for all other outlines. +// 3. a scheme is needed to tell a castellated edge from a plain board edge + +#include #include #include #include @@ -137,12 +145,24 @@ static void CALLBACK vrml_tess_err( GLenum errorID, void* user_data ) } -static void CALLBACK vrml_tess_combine( GLdouble coords[3], void* vertex_data[4], +static void CALLBACK vrml_tess_combine( GLdouble coords[3], VERTEX_3D* vertex_data[4], GLfloat weight[4], void** outData, void* user_data ) { VRML_LAYER* lp = (VRML_LAYER*) user_data; - *outData = lp->AddExtraVertex( coords[0], coords[1] ); + // the plating is set to true only if all are plated + bool plated = vertex_data[0]->pth; + + if( !vertex_data[1]->pth ) + plated = false; + + if( vertex_data[2] && !vertex_data[2]->pth ) + plated = false; + + if( vertex_data[3] && !vertex_data[3]->pth ) + plated = false; + + *outData = lp->AddExtraVertex( coords[0], coords[1], plated ); } @@ -152,6 +172,8 @@ VRML_LAYER::VRML_LAYER() maxArcSeg = 48; minSegLength = 0.1; maxSegLength = 0.5; + offsetX = 0.0; + offsetY = 0.0; fix = false; Fault = false; @@ -230,6 +252,8 @@ void VRML_LAYER::Clear( void ) contours.pop_back(); } + pth.clear(); + areas.clear(); for( i = vertices.size(); i > 0; --i ) @@ -254,6 +278,7 @@ void VRML_LAYER::clearTmp( void ) glcmd = 0; triplets.clear(); + solid.clear(); for( i = outline.size(); i > 0; --i ) { @@ -283,7 +308,7 @@ void VRML_LAYER::clearTmp( void ) // create a new contour to be populated; returns an index // into the contour list or -1 if there are problems -int VRML_LAYER::NewContour( void ) +int VRML_LAYER::NewContour( bool aPlatedHole ) { if( fix ) return -1; @@ -296,6 +321,8 @@ int VRML_LAYER::NewContour( void ) contours.push_back( contour ); areas.push_back( 0.0 ); + pth.push_back( aPlatedHole ); + return contours.size() - 1; } @@ -329,6 +356,7 @@ bool VRML_LAYER::AddVertex( int aContourID, double aXpos, double aYpos ) vertex->y = aYpos; vertex->i = idx++; vertex->o = -1; + vertex->pth = pth[ aContourID ]; VERTEX_3D* v2 = NULL; @@ -440,9 +468,15 @@ bool VRML_LAYER::AppendCircle( double aXpos, double aYpos, // adds a circle the existing list; if 'hole' is true the contour is // a hole. Returns true if OK. -bool VRML_LAYER::AddCircle( double aXpos, double aYpos, double aRadius, bool aHoleFlag ) +bool VRML_LAYER::AddCircle( double aXpos, double aYpos, double aRadius, + bool aHoleFlag, bool aPlatedHole ) { - int pad = NewContour(); + int pad; + + if( aHoleFlag && aPlatedHole ) + pad = NewContour( true ); + else + pad = NewContour( false ); if( pad < 0 ) { @@ -458,7 +492,7 @@ bool VRML_LAYER::AddCircle( double aXpos, double aYpos, double aRadius, bool aHo // contour is a hole. Returns true if OK. bool VRML_LAYER::AddSlot( double aCenterX, double aCenterY, double aSlotLength, double aSlotWidth, - double aAngle, bool aHoleFlag ) + double aAngle, bool aHoleFlag, bool aPlatedHole ) { aAngle *= M_PI / 180.0; @@ -480,7 +514,12 @@ bool VRML_LAYER::AddSlot( double aCenterX, double aCenterY, double ang, da; int i; - int pad = NewContour(); + int pad; + + if( aHoleFlag && aPlatedHole ) + pad = NewContour( true ); + else + pad = NewContour( false ); if( pad < 0 ) { @@ -578,7 +617,7 @@ bool VRML_LAYER::AppendArc( double aCenterX, double aCenterY, double aRadius, // adds an arc with the given center, start point, pen width, and angle (degrees). bool VRML_LAYER::AddArc( double aCenterX, double aCenterY, double aStartX, double aStartY, - double aArcWidth, double aAngle, bool aHoleFlag ) + double aArcWidth, double aAngle, bool aHoleFlag, bool aPlatedHole ) { aAngle *= M_PI / 180.0; @@ -636,7 +675,12 @@ bool VRML_LAYER::AddArc( double aCenterX, double aCenterY, double aStartX, doubl std::swap( iendy, isty ); } - int arc = NewContour(); + int arc; + + if( aHoleFlag && aPlatedHole ) + arc = NewContour( true ); + else + arc = NewContour( false ); if( arc < 0 ) { @@ -688,7 +732,7 @@ bool VRML_LAYER::AddArc( double aCenterX, double aCenterY, double aStartX, doubl // tesselates the contours in preparation for a 3D output; // returns true if all was fine, false otherwise -bool VRML_LAYER::Tesselate( VRML_LAYER* holes ) +bool VRML_LAYER::Tesselate( VRML_LAYER* holes, bool aHolesOnly ) { if( !tess ) { @@ -699,6 +743,12 @@ bool VRML_LAYER::Tesselate( VRML_LAYER* holes ) pholes = holes; Fault = false; + if( aHolesOnly ) + gluTessProperty( tess, GLU_TESS_WINDING_RULE, GLU_TESS_WINDING_NEGATIVE ); + else + gluTessProperty( tess, GLU_TESS_WINDING_RULE, GLU_TESS_WINDING_POSITIVE ); + + if( contours.size() < 1 || vertices.size() < 3 ) { error = "Tesselate(): not enough vertices"; @@ -736,9 +786,37 @@ bool VRML_LAYER::Tesselate( VRML_LAYER* holes ) eidx = idx + hidx; + if( aHolesOnly && ( checkNContours( true ) == 0 ) ) + { + error = "tesselate(): no hole contours"; + return false; + } + else if( !aHolesOnly && ( checkNContours( false ) == 0 ) ) + { + error = "tesselate(): no solid contours"; + return false; + } + // open the polygon gluTessBeginPolygon( tess, this ); + if( aHolesOnly ) + { + pholes = NULL; // do not accept foreign holes + hidx = 0; + eidx = idx; + + // add holes + pushVertices( true ); + + gluTessEndPolygon( tess ); + + if( Fault ) + return false; + + return true; + } + // add solid outlines pushVertices( false ); @@ -748,6 +826,13 @@ bool VRML_LAYER::Tesselate( VRML_LAYER* holes ) if( Fault ) return false; + // if there are no outlines we cannot proceed + if( outline.empty() ) + { + error = "tesselate(): no points in result"; + return false; + } + // at this point we have a solid outline; add it to the tesselator gluTessBeginPolygon( tess, this ); @@ -793,6 +878,7 @@ bool VRML_LAYER::Tesselate( VRML_LAYER* holes ) // close the polygon; this creates the outline points // and the point ordering list 'ordmap' + solid.clear(); gluTessEndPolygon( tess ); // repeat the last operation but request a tesselated surface @@ -825,6 +911,8 @@ bool VRML_LAYER::pushOutline( VRML_LAYER* holes ) std::list*>::const_iterator obeg = outline.begin(); std::list*>::const_iterator oend = outline.end(); + int nc = 0; // number of contours pushed + int pi; std::list::const_iterator begin; std::list::const_iterator end; @@ -876,6 +964,13 @@ bool VRML_LAYER::pushOutline( VRML_LAYER* holes ) gluTessEndContour( tess ); ++obeg; + ++nc; + } + + if( !nc ) + { + error = "pushOutline():: no valid contours available"; + return false; } return true; @@ -902,7 +997,7 @@ bool VRML_LAYER::WriteVertices( double aZcoord, std::ofstream& aOutFile, int aPr return false; std::string strx, stry, strz; - FormatDoublet( vp->x, vp->y, aPrecision, strx, stry ); + FormatDoublet( vp->x + offsetX, vp->y + offsetY, aPrecision, strx, stry ); FormatSinglet( aZcoord, aPrecision, strz ); aOutFile << strx << " " << stry << " " << strz; @@ -914,7 +1009,7 @@ bool VRML_LAYER::WriteVertices( double aZcoord, std::ofstream& aOutFile, int aPr if( !vp ) return false; - FormatDoublet( vp->x, vp->y, aPrecision, strx, stry ); + FormatDoublet( vp->x + offsetX, vp->y + offsetY, aPrecision, strx, stry ); if( i & 1 ) aOutFile << ", " << strx << " " << stry << " " << strz; @@ -954,7 +1049,7 @@ bool VRML_LAYER::Write3DVertices( double aTopZ, double aBottomZ, return false; std::string strx, stry, strz; - FormatDoublet( vp->x, vp->y, aPrecision, strx, stry ); + FormatDoublet( vp->x + offsetX, vp->y + offsetY, aPrecision, strx, stry ); FormatSinglet( aTopZ, aPrecision, strz ); aOutFile << strx << " " << stry << " " << strz; @@ -966,7 +1061,7 @@ bool VRML_LAYER::Write3DVertices( double aTopZ, double aBottomZ, if( !vp ) return false; - FormatDoublet( vp->x, vp->y, aPrecision, strx, stry ); + FormatDoublet( vp->x + offsetX, vp->y + offsetY, aPrecision, strx, stry ); if( i & 1 ) aOutFile << ", " << strx << " " << stry << " " << strz; @@ -976,7 +1071,7 @@ bool VRML_LAYER::Write3DVertices( double aTopZ, double aBottomZ, // repeat for the bottom layer vp = getVertexByIndex( ordmap[0], pholes ); - FormatDoublet( vp->x, vp->y, aPrecision, strx, stry ); + FormatDoublet( vp->x + offsetX, vp->y + offsetY, aPrecision, strx, stry ); FormatSinglet( aBottomZ, aPrecision, strz ); bool endl; @@ -995,7 +1090,7 @@ bool VRML_LAYER::Write3DVertices( double aTopZ, double aBottomZ, for( i = 1, j = ordmap.size(); i < j; ++i ) { vp = getVertexByIndex( ordmap[i], pholes ); - FormatDoublet( vp->x, vp->y, aPrecision, strx, stry ); + FormatDoublet( vp->x + offsetX, vp->y + offsetY, aPrecision, strx, stry ); if( endl ) { @@ -1064,68 +1159,73 @@ bool VRML_LAYER::WriteIndices( bool aTopFlag, std::ofstream& aOutFile ) // writes out the index list for a 3D feature -bool VRML_LAYER::Write3DIndices( std::ofstream& aOutFile ) +bool VRML_LAYER::Write3DIndices( std::ofstream& aOutFile, bool aIncludePlatedHoles ) { - if( triplets.empty() ) - { - error = "Write3DIndices(): no triplets (triangular facets) to write"; - return false; - } - if( outline.empty() ) { error = "WriteIndices(): no outline available"; return false; } - // go through the triplet list and write out the indices based on order - std::list::const_iterator tbeg = triplets.begin(); - std::list::const_iterator tend = triplets.end(); + char mark; + bool holes_only = triplets.empty(); int i = 1; int idx2 = ordmap.size(); // index to the bottom vertices - // print out the top vertices - aOutFile << tbeg->i1 << ", " << tbeg->i2 << ", " << tbeg->i3 << ", -1"; - ++tbeg; - - while( tbeg != tend ) + if( !holes_only ) { - if( (i++ & 7) == 4 ) - { - i = 1; - aOutFile << ",\n" << tbeg->i1 << ", " << tbeg->i2 << ", " << tbeg->i3 << ", -1"; - } - else - { - aOutFile << ", " << tbeg->i1 << ", " << tbeg->i2 << ", " << tbeg->i3 << ", -1"; - } + mark = ','; + // go through the triplet list and write out the indices based on order + std::list::const_iterator tbeg = triplets.begin(); + std::list::const_iterator tend = triplets.end(); + + // print out the top vertices + aOutFile << tbeg->i1 << ", " << tbeg->i2 << ", " << tbeg->i3 << ", -1"; ++tbeg; - } - // print out the bottom vertices - tbeg = triplets.begin(); + while( tbeg != tend ) + { + if( (i++ & 7) == 4 ) + { + i = 1; + aOutFile << ",\n" << tbeg->i1 << ", " << tbeg->i2 << ", " << tbeg->i3 << ", -1"; + } + else + { + aOutFile << ", " << tbeg->i1 << ", " << tbeg->i2 << ", " << tbeg->i3 << ", -1"; + } - while( tbeg != tend ) - { - if( (i++ & 7) == 4 ) - { - i = 1; - aOutFile << ",\n" << (tbeg->i2 + idx2) << ", " << (tbeg->i1 + idx2) << ", " << (tbeg->i3 + idx2) << ", -1"; - } - else - { - aOutFile << ", " << (tbeg->i2 + idx2) << ", " << (tbeg->i1 + idx2) << ", " << (tbeg->i3 + idx2) << ", -1"; + ++tbeg; } - ++tbeg; + // print out the bottom vertices + tbeg = triplets.begin(); + + while( tbeg != tend ) + { + if( (i++ & 7) == 4 ) + { + i = 1; + aOutFile << ",\n" << (tbeg->i2 + idx2) << ", " << (tbeg->i1 + idx2) << ", " << (tbeg->i3 + idx2) << ", -1"; + } + else + { + aOutFile << ", " << (tbeg->i2 + idx2) << ", " << (tbeg->i1 + idx2) << ", " << (tbeg->i3 + idx2) << ", -1"; + } + + ++tbeg; + } } + else + mark = ' '; + // print out indices for the walls joining top to bottom - int firstPoint; int lastPoint; int curPoint; + int curContour = 0; std::list*>::const_iterator obeg = outline.begin(); std::list*>::const_iterator oend = outline.end(); @@ -1141,22 +1241,71 @@ bool VRML_LAYER::Write3DIndices( std::ofstream& aOutFile ) if( cp->size() < 3 ) { ++obeg; + ++curContour; continue; } - cbeg = cp->begin(); - cend = cp->end(); + cbeg = cp->begin(); + cend = cp->end(); + lastPoint = *(cbeg++); - firstPoint = *(cbeg++); - lastPoint = firstPoint; + // skip all PTH vertices which are not in a solid outline + if( !aIncludePlatedHoles && !solid[curContour] + && getVertexByIndex( ordmap[lastPoint], pholes )->pth ) + { + ++obeg; + ++curContour; + continue; + } while( cbeg != cend ) { curPoint = *(cbeg++); + if( !holes_only ) + { + if( (i++ & 3) == 2 ) + { + i = 1; + aOutFile << mark << "\n" << curPoint << ", " << lastPoint << ", " << curPoint + idx2; + aOutFile << ", -1, " << curPoint + idx2 << ", " << lastPoint << ", " << lastPoint + idx2 << ", -1"; + } + else + { + aOutFile << mark << " " << curPoint << ", " << lastPoint << ", " << curPoint + idx2; + aOutFile << ", -1, " << curPoint + idx2 << ", " << lastPoint << ", " << lastPoint + idx2 << ", -1"; + } + } + else + { + if( (i++ & 3) == 2 ) + { + i = 1; + aOutFile << mark << "\n" << curPoint << ", " << curPoint + idx2 << ", " << lastPoint; + aOutFile << ", -1, " << curPoint + idx2 << ", " << lastPoint + idx2 << ", " << lastPoint << ", -1"; + } + else + { + aOutFile << mark << " " << curPoint << ", " << curPoint + idx2 << ", " << lastPoint; + aOutFile << ", -1, " << curPoint + idx2 << ", " << lastPoint + idx2 << ", " << lastPoint << ", -1"; + } + } + + mark = ','; + lastPoint = curPoint; + } + + // check if the loop needs to be closed + cbeg = cp->begin(); + cend = --cp->end(); + + curPoint = *(cbeg); + lastPoint = *(cend); + + if( !holes_only ) + { if( (i++ & 3) == 2 ) { - i = 1; aOutFile << ",\n" << curPoint << ", " << lastPoint << ", " << curPoint + idx2; aOutFile << ", -1, " << curPoint + idx2 << ", " << lastPoint << ", " << lastPoint + idx2 << ", -1"; } @@ -1165,21 +1314,23 @@ bool VRML_LAYER::Write3DIndices( std::ofstream& aOutFile ) aOutFile << ", " << curPoint << ", " << lastPoint << ", " << curPoint + idx2; aOutFile << ", -1, " << curPoint + idx2 << ", " << lastPoint << ", " << lastPoint + idx2 << ", -1"; } - lastPoint = curPoint; - } - - if( (i++ & 3) == 2 ) - { - aOutFile << ",\n" << firstPoint << ", " << lastPoint << ", " << firstPoint + idx2; - aOutFile << ", -1, " << firstPoint + idx2 << ", " << lastPoint << ", " << lastPoint + idx2 << ", -1"; } else { - aOutFile << ", " << firstPoint << ", " << lastPoint << ", " << firstPoint + idx2; - aOutFile << ", -1, " << firstPoint + idx2 << ", " << lastPoint << ", " << lastPoint + idx2 << ", -1"; + if( (i++ & 3) == 2 ) + { + aOutFile << ",\n" << curPoint << ", " << curPoint + idx2 << ", " << lastPoint; + aOutFile << ", -1, " << curPoint + idx2 << ", " << lastPoint + idx2 << ", " << lastPoint << ", -1"; + } + else + { + aOutFile << ", " << curPoint << ", " << curPoint + idx2 << ", " << lastPoint; + aOutFile << ", -1, " << curPoint + idx2 << ", " << lastPoint + idx2 << ", " << lastPoint << ", -1"; + } } ++obeg; + ++curContour; } return !aOutFile.fail(); @@ -1222,7 +1373,7 @@ bool VRML_LAYER::addTriplet( VERTEX_3D* p0, VERTEX_3D* p1, VERTEX_3D* p2 ) // add an extra vertex (to be called only by the COMBINE callback) -VERTEX_3D* VRML_LAYER::AddExtraVertex( double aXpos, double aYpos ) +VERTEX_3D* VRML_LAYER::AddExtraVertex( double aXpos, double aYpos, bool aPlatedHole ) { VERTEX_3D* vertex = new VERTEX_3D; @@ -1239,6 +1390,7 @@ VERTEX_3D* VRML_LAYER::AddExtraVertex( double aXpos, double aYpos ) vertex->y = aYpos; vertex->i = eidx++; vertex->o = -1; + vertex->pth = aPlatedHole; extra_verts.push_back( vertex ); @@ -1282,12 +1434,39 @@ void VRML_LAYER::glEnd( void ) if( !loop ) break; - for( unsigned int i = 0; i < vlist.size(); ++i ) + double firstX = 0.0; + double firstY = 0.0; + double lastX, lastY; + double curX, curY; + double area = 0.0; + + if( vlist.size() > 0 ) { - loop->push_back( vlist[i]->o ); + loop->push_back( vlist[0]->o ); + firstX = vlist[0]->x; + firstY = vlist[0]->y; + lastX = firstX; + lastY = firstY; } + for( size_t i = 1; i < vlist.size(); ++i ) + { + loop->push_back( vlist[i]->o ); + curX = vlist[i]->x; + curY = vlist[i]->y; + area += ( curX - lastX ) * ( curY + lastY ); + lastX = curX; + lastY = curY; + } + + area += ( firstX - lastX ) * ( firstY + lastY ); + outline.push_back( loop ); + + if( area <= 0.0 ) + solid.push_back( true ); + else + solid.push_back( false ); } break; @@ -1398,6 +1577,31 @@ void VRML_LAYER::processTri( void ) } +int VRML_LAYER::checkNContours( bool holes ) +{ + int nc = 0; // number of contours + + if( contours.empty() ) + return 0; + + std::list::const_iterator begin; + std::list::const_iterator end; + + for( size_t i = 0; i < contours.size(); ++i ) + { + if( contours[i]->size() < 3 ) + continue; + + if( ( holes && areas[i] <= 0.0 ) || ( !holes && areas[i] > 0.0 ) ) + continue; + + ++nc; + } + + return nc; +} + + // push the internally held vertices void VRML_LAYER::pushVertices( bool holes ) { @@ -1434,6 +1638,8 @@ void VRML_LAYER::pushVertices( bool holes ) gluTessEndContour( tess ); } + + return; } @@ -1564,3 +1770,11 @@ const std::string& VRML_LAYER::GetError( void ) { return error; } + + +void VRML_LAYER::SetVertexOffsets( double aXoffset, double aYoffset ) +{ + offsetX = aXoffset; + offsetY = aYoffset; + return; +} diff --git a/utils/idftools/vrml_layer.h b/utils/idftools/vrml_layer.h index 5316b62506..01e4f343cb 100644 --- a/utils/idftools/vrml_layer.h +++ b/utils/idftools/vrml_layer.h @@ -70,6 +70,7 @@ struct VERTEX_3D double y; int i; // vertex index int o; // vertex order + bool pth; // true for plate-through hole }; struct TRIPLET_3D @@ -93,12 +94,18 @@ private: double minSegLength; // min. segment length double maxSegLength; // max. segment length + // Vertex offsets to work around a suspected GLU tesselator bug + double offsetX; + double offsetY; + bool fix; // when true, no more vertices may be added by the user int idx; // vertex index (number of contained vertices) int ord; // vertex order (number of ordered vertices) unsigned int idxout; // outline index to first point in 3D outline std::vector vertices; // vertices of all contours std::vector*> contours; // lists of vertices for each contour + std::vectorpth; // indicates whether a 'contour' is a PTH or not + std::vectorsolid; // indicates whether a 'contour' is a solid or a hole std::vector< double > areas; // area of the contours (positive if winding is CCW) std::list triplets; // output facet triplet list (triplet of ORDER values) std::list*> outline; // indices for outline outputs (index by ORDER values) @@ -136,6 +143,9 @@ private: // calculate number of sides on an arc (angle is in radians) int calcNSides( double aRadius, double aAngle ); + // returns the number of solid or hole contours + int checkNContours( bool holes ); + public: /// set to true when a fault is encountered during tesselation bool Fault; @@ -191,9 +201,11 @@ public: * Function NewContour * creates a new list of vertices and returns an index to the list * + * @param aPlatedHole is true if the new contour will represent a plated hole + * * @return int: index to the list or -1 if the operation failed */ - int NewContour( void ); + int NewContour( bool aPlatedHole = false ); /** * Function AddVertex @@ -231,7 +243,8 @@ public: * * @return bool: true if the new contour was successfully created */ - bool AppendCircle( double aXpos, double aYpos, double aRadius, int aContourID, bool aHoleFlag = false ); + bool AppendCircle( double aXpos, double aYpos, double aRadius, + int aContourID, bool aHoleFlag = false ); /** * Function AddCircle @@ -241,10 +254,12 @@ public: * @param aYpos is the Y coordinate of the hole center * @param aRadius is the radius of the hole * @param aHoleFlag determines if the contour to be created is a cutout + * @param aPlatedHole is true if this is a plated hole * * @return bool: true if the new contour was successfully created */ - bool AddCircle( double aXpos, double aYpos, double aRadius, bool aHoleFlag = false ); + bool AddCircle( double aXpos, double aYpos, double aRadius, + bool aHoleFlag = false, bool aPlatedHole = false ); /** * Function AddSlot @@ -256,11 +271,12 @@ public: * @param aSlotWidth is the width of the slot along the minor axis * @param aAngle (degrees) is the orientation of the slot * @param aHoleFlag determines whether the slot is a hole or a solid + * @param aPlatedHole is true if this is a plated slot * * @return bool: true if the slot was successfully created */ bool AddSlot( double aCenterX, double aCenterY, double aSlotLength, double aSlotWidth, - double aAngle, bool aHoleFlag = false ); + double aAngle, bool aHoleFlag = false, bool aPlatedHole = false ); /** * Function AppendArc @@ -289,11 +305,14 @@ public: * @param aArcWidth is the width of the arc * @param aAngle is the included angle (degrees) * @param aHoleFlag determines whether the arc is to be a hole or a solid + * @param aPlatedHole is true if this is a plated slotted arc * * @return bool: true if the feature was successfully created */ - bool AddArc( double aCenterX, double aCenterY, double aStartX, double aStartY, - double aArcWidth, double aAngle, bool aHoleFlag = false ); + bool AddArc( double aCenterX, double aCenterY, + double aStartX, double aStartY, + double aArcWidth, double aAngle, + bool aHoleFlag = false, bool aPlatedHole = false ); /** * Function Tesselate @@ -301,11 +320,12 @@ public: * vertex sets required to render the surface. * * @param holes is an optional pointer to cutouts to be imposed on the - * surface. + * surface. + * @param aHolesOnly is true if the outline contains only holes * * @return bool: true if the operation succeeded */ - bool Tesselate( VRML_LAYER* holes = NULL ); + bool Tesselate( VRML_LAYER* holes = NULL, bool aHolesOnly = false ); /** * Function WriteVertices @@ -351,19 +371,26 @@ public: * writes out the vertex sets required to render an extruded solid * * @param aOutFile is the file to write to + * @param aIncludePlatedHoles is true if holes marked as plated should + * be rendered. Default is false since the user will usually + * render these holes in a different color * * @return bool: true if the operation succeeded */ - bool Write3DIndices( std::ofstream& aOutFile ); + bool Write3DIndices( std::ofstream& aOutFile, bool aIncludePlatedHoles = false ); /** * Function AddExtraVertex - * adds an extra vertex as required by the GLU tesselator + * adds an extra vertex as required by the GLU tesselator. + * + * @param aXpos is the X coordinate of the newly created point + * @param aYpos is the Y coordinate of the newly created point + * @param aPlatedHole is true if this point is part of a plated hole * * @return VERTEX_3D*: is the new vertex or NULL if a vertex * could not be created. */ - VERTEX_3D* AddExtraVertex( double aXpos, double aYpos ); + VERTEX_3D* AddExtraVertex( double aXpos, double aYpos, bool aPlatedHole ); /** * Function glStart @@ -429,6 +456,8 @@ public: * Returns the error message related to the last failed operation */ const std::string& GetError( void ); + + void SetVertexOffsets( double aXoffset, double aYoffset ); }; #endif // VRML_LAYER_H