static void export_vrml_circle( MODEL_VRML& aModel, LAYER_NUM layer, double startx, double starty, double endx, double endy, double width ) { VRML_LAYER* vlayer; if( !GetLayer( aModel, layer, &vlayer ) ) return; if( width < aModel.minLineWidth ) width = aModel.minLineWidth; starty = -starty; endy = -endy; double hole, radius; radius = Distance( startx, starty, endx, endy ) + ( width / 2); hole = radius - width; if( !vlayer->AddCircle( startx, starty, radius, false ) ) throw( std::runtime_error( vlayer->GetError() ) ); if( hole > 0.0001 ) { if( !vlayer->AddCircle( startx, starty, hole, true ) ) throw( std::runtime_error( vlayer->GetError() ) ); } }
static void CALLBACK vrml_tess_combine( GLdouble coords[3], void* 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] ); }
static SCENEGRAPH* addOutline( IDF3_COMP_OUTLINE* outline, int idxColor, SGNODE* aParent ) { VRML_LAYER vpcb; if( !getOutlineModel( vpcb, outline->GetOutlines() ) ) { #ifdef DEBUG do { std::ostringstream ostr; std::cerr << __FILE__ << ": " << __FUNCTION__ << ": " << __LINE__ << "\n"; std::cerr << " * [INFO] no valid outline data"; wxLogTrace( MASK_IDF, "%s\n", ostr.str().c_str() ); } while( 0 ); #endif return NULL; } vpcb.EnsureWinding( 0, false ); double top = outline->GetThickness(); double bot = 0.0; // note: some IDF entities permit negative heights if( top < bot ) { bot = top; top = 0.0; } SCENEGRAPH* data = vrmlToSG( vpcb, idxColor, aParent, top, bot ); return data; }
static void CALLBACK vrml_tess_err( GLenum errorID, void* user_data ) { VRML_LAYER* lp = (VRML_LAYER*) user_data; lp->Fault = true; lp->SetGLError( errorID ); }
static void export_vrml_zones( MODEL_VRML& aModel, BOARD* aPcb ) { double scale = aModel.scale; double x, y; for( int ii = 0; ii < aPcb->GetAreaCount(); ii++ ) { ZONE_CONTAINER* zone = aPcb->GetArea( ii ); VRML_LAYER* vl; if( !GetLayer( aModel, zone->GetLayer(), &vl ) ) continue; if( !zone->IsFilled() ) { zone->SetFillMode( 0 ); // use filled polygons zone->BuildFilledSolidAreasPolygons( aPcb ); } const CPOLYGONS_LIST& poly = zone->GetFilledPolysList(); int nvert = poly.GetCornersCount(); int i = 0; while( i < nvert ) { int seg = vl->NewContour(); bool first = true; if( seg < 0 ) break; while( i < nvert ) { x = poly.GetX(i) * scale; y = -(poly.GetY(i) * scale); if( poly.IsEndContour(i) ) break; if( !vl->AddVertex( seg, x, y ) ) throw( std::runtime_error( vl->GetError() ) ); ++i; } // KiCad ensures that the first polygon is the outline // and all others are holes vl->EnsureWinding( seg, first ? false : true ); if( first ) first = false; ++i; } } }
// set the scaling of the VRML world bool SetScale( double aWorldScale ) { if( aWorldScale < 0.001 || aWorldScale > 10.0 ) throw( std::runtime_error( "WorldScale out of range (valid range is 0.001 to 10.0)" ) ); scale = aWorldScale * MM_PER_IU; minLineWidth = aWorldScale * MIN_VRML_LINEWIDTH; // set the precision of the VRML coordinates if( aWorldScale < 0.01 ) precision = 8; else if( aWorldScale < 0.1 ) precision = 7; else if( aWorldScale< 1.0 ) precision = 6; else if( aWorldScale < 10.0 ) precision = 5; else precision = 4; double smin = arcMinLen * aWorldScale; double smax = arcMaxLen * aWorldScale; holes.SetArcParams( iMaxSeg, smin, smax ); board.SetArcParams( iMaxSeg, smin, smax ); top_copper.SetArcParams( iMaxSeg, smin, smax); bot_copper.SetArcParams( iMaxSeg, smin, smax); top_silk.SetArcParams( iMaxSeg, smin, smax ); 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; }
MODEL_VRML() { for( unsigned i = 0; i < DIM( layer_z ); ++i ) layer_z[i] = 0; holes.GetArcParams( iMaxSeg, arcMinLen, arcMaxLen ); // this default only makes sense if the output is in mm board_thickness = 1.6; // pcb green colors[ VRML_COLOR_PCB ] = VRML_COLOR( .07, .3, .12, .07, .3, .12, 0, 0, 0, 1, 0, 0.2 ); // track green colors[ VRML_COLOR_TRACK ] = VRML_COLOR( .08, .5, .1, .08, .5, .1, 0, 0, 0, 1, 0, 0.2 ); // silkscreen white colors[ VRML_COLOR_SILK ] = VRML_COLOR( .9, .9, .9, .9, .9, .9, 0, 0, 0, 1, 0, 0.2 ); // pad silver colors[ VRML_COLOR_TIN ] = VRML_COLOR( .749, .756, .761, .749, .756, .761, 0, 0, 0, 0.8, 0, 0.8 ); precision = 5; }
void SetOffset( double aXoff, double 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 ); }
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; // 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 ); }
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 ) { VRML_LAYER* vlayer; if( !GetLayer( aModel, layer, &vlayer ) ) return; if( width < aModel.minLineWidth ) width = aModel.minLineWidth; centery = -centery; arc_starty = -arc_starty; if( !vlayer->AddArc( centerx, centery, arc_startx, arc_starty, width, arc_angle, false ) ) throw( std::runtime_error( vlayer->GetError() ) ); }
static void export_vrml_line( MODEL_VRML& aModel, LAYER_NUM layer, double startx, double starty, double endx, double endy, double width ) { VRML_LAYER* vlayer; if( !GetLayer( aModel, layer, &vlayer ) ) return; if( width < aModel.minLineWidth) width = aModel.minLineWidth; starty = -starty; endy = -endy; double angle = atan2( endy - starty, endx - startx ) * 180.0 / M_PI; double length = Distance( startx, starty, endx, endy ) + width; double cx = ( startx + endx ) / 2.0; double cy = ( starty + endy ) / 2.0; if( !vlayer->AddSlot( cx, cy, length, width, angle, false ) ) throw( std::runtime_error( vlayer->GetError() ) ); }
static bool addSegment( VRML_LAYER& model, IDF_SEGMENT* seg, int icont, int iseg ) { // note: in all cases we must add all but the last point in the segment // to avoid redundant points if( seg->angle != 0.0 ) { if( seg->IsCircle() ) { if( iseg != 0 ) { #ifdef DEBUG do { std::ostringstream ostr; std::cerr << __FILE__ << ": " << __FUNCTION__ << ": " << __LINE__ << "\n"; std::cerr << " * [INFO] adding a circle to an existing vertex list"; wxLogTrace( MASK_IDF, "%s\n", ostr.str().c_str() ); } while( 0 ); #endif return false; } return model.AppendCircle( seg->center.x, seg->center.y, seg->radius, icont ); } else { return model.AppendArc( seg->center.x, seg->center.y, seg->radius, seg->offsetAngle, seg->angle, icont ); } } if( !model.AddVertex( icont, seg->startPoint.x, seg->startPoint.y ) ) return false; return true; }
static void CALLBACK vrml_tess_end( void* user_data ) { VRML_LAYER* lp = (VRML_LAYER*) user_data; lp->glEnd(); }
static bool getOutlineModel( VRML_LAYER& model, const std::list< IDF_OUTLINE* >* items ) { // empty outlines are not unusual so we fail quietly if( items->size() < 1 ) return false; int nvcont = 0; int iseg = 0; std::list< IDF_OUTLINE* >::const_iterator scont = items->begin(); std::list< IDF_OUTLINE* >::const_iterator econt = items->end(); std::list<IDF_SEGMENT*>::iterator sseg; std::list<IDF_SEGMENT*>::iterator eseg; IDF_SEGMENT lseg; while( scont != econt ) { nvcont = model.NewContour(); if( nvcont < 0 ) { #ifdef DEBUG do { std::ostringstream ostr; std::cerr << __FILE__ << ": " << __FUNCTION__ << ": " << __LINE__ << "\n"; std::cerr << " * [INFO] cannot create an outline"; wxLogTrace( MASK_IDF, "%s\n", ostr.str().c_str() ); } while( 0 ); #endif return false; } if( (*scont)->size() < 1 ) { #ifdef DEBUG do { std::ostringstream ostr; std::cerr << __FILE__ << ": " << __FUNCTION__ << ": " << __LINE__ << "\n"; std::cerr << " * [INFO] invalid contour: no vertices"; wxLogTrace( MASK_IDF, "%s\n", ostr.str().c_str() ); } while( 0 ); #endif return false; } sseg = (*scont)->begin(); eseg = (*scont)->end(); iseg = 0; while( sseg != eseg ) { lseg = **sseg; if( !addSegment( model, &lseg, nvcont, iseg ) ) { #ifdef DEBUG do { std::ostringstream ostr; std::cerr << __FILE__ << ": " << __FUNCTION__ << ": " << __LINE__ << "\n"; std::cerr << " * [BUG] cannot add segment"; wxLogTrace( MASK_IDF, "%s\n", ostr.str().c_str() ); } while( 0 ); #endif return false; } ++iseg; ++sseg; } ++scont; } return true; }
static void CALLBACK vrml_tess_begin( GLenum cmd, void* user_data ) { VRML_LAYER* lp = (VRML_LAYER*) user_data; lp->glStart( cmd ); }
static bool makeOtherOutlines( IDF3_BOARD& brd, SGNODE* aParent ) { if( NULL == aParent ) return false; VRML_LAYER vpcb; int ncomponents = 0; double brdTop = brd.GetBoardThickness(); double top, bot; // Add the component outlines const std::map< std::string, OTHER_OUTLINE* >*const comp = brd.GetOtherOutlines(); std::map< std::string, OTHER_OUTLINE* >::const_iterator sc = comp->begin(); std::map< std::string, OTHER_OUTLINE* >::const_iterator ec = comp->end(); int nvcont; OTHER_OUTLINE* pout; while( sc != ec ) { pout = sc->second; if( std::abs( pout->GetThickness() ) < 0.001 ) { ++sc; continue; } if( !getOutlineModel( vpcb, pout->GetOutlines() ) ) { vpcb.Clear(); ++sc; continue; } vpcb.EnsureWinding( 0, false ); nvcont = vpcb.GetNContours() - 1; while( nvcont > 0 ) vpcb.EnsureWinding( nvcont--, true ); if( pout->GetSide() == IDF3::LYR_BOTTOM ) { top = 0.0; bot = -pout->GetThickness(); } else { bot = brdTop; top = bot + pout->GetThickness(); } if( NULL == vrmlToSG( vpcb, -1, aParent, top, bot ) ) { vpcb.Clear(); ++sc; continue; } ++ncomponents; vpcb.Clear(); ++sc; } if( 0 == ncomponents ) return false; return true; }
static SCENEGRAPH* makeBoard( IDF3_BOARD& brd, SGNODE* aParent ) { if( NULL == aParent ) return NULL; VRML_LAYER vpcb; // check if no board outline if( brd.GetBoardOutlinesSize() < 1 ) return NULL; if( !getOutlineModel( vpcb, brd.GetBoardOutline()->GetOutlines() ) ) return NULL; vpcb.EnsureWinding( 0, false ); int nvcont = vpcb.GetNContours() - 1; while( nvcont > 0 ) vpcb.EnsureWinding( nvcont--, true ); // Add the drill holes const std::list<IDF_DRILL_DATA*>* drills = &brd.GetBoardDrills(); std::list<IDF_DRILL_DATA*>::const_iterator sd = drills->begin(); std::list<IDF_DRILL_DATA*>::const_iterator ed = drills->end(); while( sd != ed ) { vpcb.AddCircle( (*sd)->GetDrillXPos(), (*sd)->GetDrillYPos(), (*sd)->GetDrillDia() / 2.0, true ); ++sd; } std::map< std::string, IDF3_COMPONENT* >*const comp = brd.GetComponents(); std::map< std::string, IDF3_COMPONENT* >::const_iterator sc = comp->begin(); std::map< std::string, IDF3_COMPONENT* >::const_iterator ec = comp->end(); while( sc != ec ) { drills = sc->second->GetDrills(); sd = drills->begin(); ed = drills->end(); while( sd != ed ) { vpcb.AddCircle( (*sd)->GetDrillXPos(), (*sd)->GetDrillYPos(), (*sd)->GetDrillDia() / 2.0, true ); ++sd; } ++sc; } double top = brd.GetBoardThickness(); SCENEGRAPH* data = vrmlToSG( vpcb, 0, aParent, top, 0.0 ); return data; }
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; 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() ) { case S_SEGMENT: export_vrml_line( aModel, layer, x, y, xf, yf, w ); break; case S_ARC: export_vrml_arc( aModel, layer, x, y, xf, yf, w, aOutline->GetAngle() / 10 ); break; case S_CIRCLE: export_vrml_circle( aModel, layer, x, y, xf, yf, w ); break; case S_POLYGON: { VRML_LAYER* vl; if( !GetLayer( aModel, layer, &vl ) ) break; int nvert = aOutline->GetPolyPoints().size() - 1; int i = 0; if( nvert < 3 ) break; int seg = vl->NewContour(); if( seg < 0 ) break; while( i < nvert ) { CPolyPt corner( aOutline->GetPolyPoints()[i] ); RotatePoint( &corner.x, &corner.y, aOrientation ); corner.x += aOutline->GetPosition().x; corner.y += aOutline->GetPosition().y; x = corner.x * aModel.scale; y = - ( corner.y * aModel.scale ); if( !vl->AddVertex( seg, x, y ) ) throw( std::runtime_error( vl->GetError() ) ); ++i; } vl->EnsureWinding( seg, false ); } break; default: break; } }
static void CALLBACK vrml_tess_vertex( void* vertex_data, void* user_data ) { VRML_LAYER* lp = (VRML_LAYER*) user_data; lp->glPushVertex( (VERTEX_3D*) vertex_data ); }