/* Redraw segment during cursor movement */ static void DrawSegment( EDA_DRAW_PANEL* aPanel, wxDC* aDC, const wxPoint& aPosition, bool aErase ) { DRAWSEGMENT* Segment = (DRAWSEGMENT*) aPanel->GetScreen()->GetCurItem(); int t_fill = DisplayOpt.DisplayDrawItems; if( Segment == NULL ) return; DisplayOpt.DisplayDrawItems = SKETCH; if( aErase ) Segment->Draw( aPanel, aDC, GR_XOR ); if( g_Segments_45_Only && Segment->GetShape() == S_SEGMENT ) { wxPoint pt; CalculateSegmentEndPoint( aPanel->GetParent()->GetCrossHairPosition(), Segment->GetStart().x, Segment->GetStart().y, &pt.x, &pt.y ); Segment->SetEnd( pt ); } else // here the angle is arbitrary { Segment->SetEnd( aPanel->GetParent()->GetCrossHairPosition() ); } Segment->Draw( aPanel, aDC, GR_XOR ); DisplayOpt.DisplayDrawItems = t_fill; }
void BRDITEMS_PLOTTER::PlotPcbTarget( PCB_TARGET* aMire ) { int dx1, dx2, dy1, dy2, radius; if( !m_layerMask[aMire->GetLayer()] ) return; m_plotter->SetColor( getColor( aMire->GetLayer() ) ); DRAWSEGMENT draw; draw.SetShape( S_CIRCLE ); draw.SetWidth( ( GetMode() == LINE ) ? -1 : aMire->GetWidth() ); draw.SetLayer( aMire->GetLayer() ); draw.SetStart( aMire->GetPosition() ); radius = aMire->GetSize() / 3; if( aMire->GetShape() ) // shape X radius = aMire->GetSize() / 2; // Draw the circle draw.SetEnd( wxPoint( draw.GetStart().x + radius, draw.GetStart().y )); PlotDrawSegment( &draw ); draw.SetShape( S_SEGMENT ); radius = aMire->GetSize() / 2; dx1 = radius; dy1 = 0; dx2 = 0; dy2 = radius; if( aMire->GetShape() ) // Shape X { dx1 = dy1 = radius; dx2 = dx1; dy2 = -dy1; } wxPoint mirePos( aMire->GetPosition() ); // Draw the X or + shape: draw.SetStart( wxPoint( mirePos.x - dx1, mirePos.y - dy1 )); draw.SetEnd( wxPoint( mirePos.x + dx1, mirePos.y + dy1 )); PlotDrawSegment( &draw ); draw.SetStart( wxPoint( mirePos.x - dx2, mirePos.y - dy2 )); draw.SetEnd( wxPoint( mirePos.x + dx2, mirePos.y + dy2 )); PlotDrawSegment( &draw ); }
/* Redraw segment during cursor movement */ static void DrawSegment( EDA_DRAW_PANEL* aPanel, wxDC* aDC, const wxPoint& aPosition, bool aErase ) { DRAWSEGMENT* Segment = (DRAWSEGMENT*) aPanel->GetScreen()->GetCurItem(); auto frame = (PCB_EDIT_FRAME*) ( aPanel->GetParent() ); if( Segment == NULL ) return; auto displ_opts = (PCB_DISPLAY_OPTIONS*) ( aPanel->GetDisplayOptions() ); bool tmp = displ_opts->m_DisplayDrawItemsFill; displ_opts->m_DisplayDrawItemsFill = SKETCH; if( aErase ) Segment->Draw( aPanel, aDC, GR_XOR ); if( frame->Settings().m_use45DegreeGraphicSegments && Segment->GetShape() == S_SEGMENT ) { wxPoint pt; pt = CalculateSegmentEndPoint( aPanel->GetParent()->GetCrossHairPosition(), Segment->GetStart() ); Segment->SetEnd( pt ); } else // here the angle is arbitrary { Segment->SetEnd( aPanel->GetParent()->GetCrossHairPosition() ); } Segment->Draw( aPanel, aDC, GR_XOR ); displ_opts->m_DisplayDrawItemsFill = tmp; }
/* Creates the section $BOARD. * We output here only the board perimeter */ static void CreateBoardSection( FILE* aFile, BOARD* aPcb ) { fputs( "$BOARD\n", aFile ); // Extract the board edges for( EDA_ITEM* drawing = aPcb->m_Drawings; drawing != 0; drawing = drawing->Next() ) { if( drawing->Type() == PCB_LINE_T ) { DRAWSEGMENT* drawseg = static_cast<DRAWSEGMENT*>( drawing ); if( drawseg->GetLayer() == Edge_Cuts ) { // XXX GenCAD supports arc boundaries but I've seen nothing that reads them fprintf( aFile, "LINE %g %g %g %g\n", MapXTo( drawseg->GetStart().x ), MapYTo( drawseg->GetStart().y ), MapXTo( drawseg->GetEnd().x ), MapYTo( drawseg->GetEnd().y ) ); } } } fputs( "$ENDBOARD\n\n", aFile ); }
/* * Redraw segment during cursor movement. */ static void Move_Segment( EDA_DRAW_PANEL* aPanel, wxDC* aDC, const wxPoint& aPosition, bool aErase ) { DRAWSEGMENT* segment = (DRAWSEGMENT*) aPanel->GetScreen()->GetCurItem(); if( segment == NULL ) return; if( aErase ) segment->Draw( aPanel, aDC, GR_XOR ); wxPoint delta; delta = aPanel->GetParent()->GetCrossHairPosition() - s_LastPosition; segment->SetStart( segment->GetStart() + delta ); segment->SetEnd( segment->GetEnd() + delta ); s_LastPosition = aPanel->GetParent()->GetCrossHairPosition(); segment->Draw( aPanel, aDC, GR_XOR ); }
/** * Function idf_export_outline * retrieves line segment information from the edge layer and compiles * the data into a form which can be output as an IDFv3 compliant * BOARD_OUTLINE section. */ static void idf_export_outline( BOARD* aPcb, IDF3_BOARD& aIDFBoard ) { double scale = aIDFBoard.GetUserScale(); DRAWSEGMENT* graphic; // KiCad graphical item IDF_POINT sp, ep; // start and end points from KiCad item std::list< IDF_SEGMENT* > lines; // IDF intermediate form of KiCad graphical item IDF_OUTLINE* outline = NULL; // graphical items forming an outline or cutout // NOTE: IMPLEMENTATION // If/when component cutouts are allowed, we must implement them separately. Cutouts // must be added to the board outline section and not to the Other Outline section. // The module cutouts should be handled via the idf_export_module() routine. double offX, offY; aIDFBoard.GetUserOffset( offX, offY ); // Retrieve segments and arcs from the board for( BOARD_ITEM* item = aPcb->m_Drawings; item; item = item->Next() ) { if( item->Type() != PCB_LINE_T || item->GetLayer() != Edge_Cuts ) continue; graphic = (DRAWSEGMENT*) item; switch( graphic->GetShape() ) { case S_SEGMENT: { if( ( graphic->GetStart().x == graphic->GetEnd().x ) && ( graphic->GetStart().y == graphic->GetEnd().y ) ) break; sp.x = graphic->GetStart().x * scale + offX; sp.y = -graphic->GetStart().y * scale + offY; ep.x = graphic->GetEnd().x * scale + offX; ep.y = -graphic->GetEnd().y * scale + offY; IDF_SEGMENT* seg = new IDF_SEGMENT( sp, ep ); if( seg ) lines.push_back( seg ); } break; case S_ARC: { if( ( graphic->GetCenter().x == graphic->GetArcStart().x ) && ( graphic->GetCenter().y == graphic->GetArcStart().y ) ) break; sp.x = graphic->GetCenter().x * scale + offX; sp.y = -graphic->GetCenter().y * scale + offY; ep.x = graphic->GetArcStart().x * scale + offX; ep.y = -graphic->GetArcStart().y * scale + offY; IDF_SEGMENT* seg = new IDF_SEGMENT( sp, ep, -graphic->GetAngle() / 10.0, true ); if( seg ) lines.push_back( seg ); } break; case S_CIRCLE: { if( graphic->GetRadius() == 0 ) break; sp.x = graphic->GetCenter().x * scale + offX; sp.y = -graphic->GetCenter().y * scale + offY; ep.x = sp.x - graphic->GetRadius() * scale; ep.y = sp.y; // Circles must always have an angle of +360 deg. to appease // quirky MCAD implementations of IDF. IDF_SEGMENT* seg = new IDF_SEGMENT( sp, ep, 360.0, true ); if( seg ) lines.push_back( seg ); } break; default: break; } } // if there is no outline then use the bounding box if( lines.empty() ) { goto UseBoundingBox; } // get the board outline and write it out // note: we do not use a try/catch block here since we intend // to simply ignore unclosed loops and continue processing // until we're out of segments to process outline = new IDF_OUTLINE; IDF3::GetOutline( lines, *outline ); if( outline->empty() ) goto UseBoundingBox; aIDFBoard.AddBoardOutline( outline ); outline = NULL; // get all cutouts and write them out while( !lines.empty() ) { if( !outline ) outline = new IDF_OUTLINE; IDF3::GetOutline( lines, *outline ); if( outline->empty() ) { outline->Clear(); continue; } aIDFBoard.AddBoardOutline( outline ); outline = NULL; } return; UseBoundingBox: // clean up if necessary while( !lines.empty() ) { delete lines.front(); lines.pop_front(); } if( outline ) outline->Clear(); else outline = new IDF_OUTLINE; // fetch a rectangular bounding box for the board; // there is always some uncertainty in the board dimensions // computed via ComputeBoundingBox() since this depends on the // individual module entities. EDA_RECT bbbox = aPcb->ComputeBoundingBox( true ); // convert to mm and compensate for an assumed LINE_WIDTH line thickness double x = ( bbbox.GetOrigin().x + LINE_WIDTH / 2 ) * scale + offX; double y = ( bbbox.GetOrigin().y + LINE_WIDTH / 2 ) * scale + offY; double dx = ( bbbox.GetSize().x - LINE_WIDTH ) * scale; double dy = ( bbbox.GetSize().y - LINE_WIDTH ) * scale; double px[4], py[4]; px[0] = x; py[0] = y; px[1] = x; py[1] = y + dy; px[2] = x + dx; py[2] = y + dy; px[3] = x + dx; py[3] = y; IDF_POINT p1, p2; p1.x = px[3]; p1.y = py[3]; p2.x = px[0]; p2.y = py[0]; outline->push( new IDF_SEGMENT( p1, p2 ) ); for( int i = 1; i < 4; ++i ) { p1.x = px[i - 1]; p1.y = py[i - 1]; p2.x = px[i]; p2.y = py[i]; outline->push( new IDF_SEGMENT( p1, p2 ) ); } aIDFBoard.AddBoardOutline( outline ); }
void DIALOG_GRAPHIC_ITEM_PROPERTIES::initDlg( ) /**************************************************************************/ /* Initialize messages and values in text control, * according to the item parameters values */ { SetFocus(); m_StandardButtonsSizerOK->SetDefault(); // Set unit symbol wxStaticText * texts_unit[] = { m_StartPointXUnit, m_StartPointYUnit, m_EndPointXUnit, m_EndPointYUnit, m_ThicknessTextUnit, m_DefaulThicknessTextUnit, NULL }; for( int ii = 0; ; ii++ ) { if( texts_unit[ii] == NULL ) break; texts_unit[ii]->SetLabel( GetAbbreviatedUnitsLabel() ); } wxString msg; // Change texts according to the segment shape: switch ( m_Item->GetShape() ) { case S_CIRCLE: m_StartPointXLabel->SetLabel(_("Center X")); m_StartPointYLabel->SetLabel(_("Center Y")); m_EndPointXLabel->SetLabel(_("Point X")); m_EndPointYLabel->SetLabel(_("Point Y")); m_Angle_Text->Show(false); m_Angle_Ctrl->Show(false); m_AngleUnit->Show(false); break; case S_ARC: m_StartPointXLabel->SetLabel(_("Center X")); m_StartPointYLabel->SetLabel(_("Center Y")); m_EndPointXLabel->SetLabel(_("Start Point X")); m_EndPointYLabel->SetLabel(_("Start Point Y")); msg << m_Item->GetAngle(); m_Angle_Ctrl->SetValue(msg); break; default: m_Angle_Text->Show(false); m_Angle_Ctrl->Show(false); m_AngleUnit->Show(false); break; } PutValueInLocalUnits( *m_Center_StartXCtrl, m_Item->GetStart().x, m_parent->GetInternalUnits() ); PutValueInLocalUnits( *m_Center_StartYCtrl, m_Item->GetStart().y, m_parent->GetInternalUnits() ); PutValueInLocalUnits( *m_EndX_Radius_Ctrl, m_Item->GetEnd().x, m_parent->GetInternalUnits() ); PutValueInLocalUnits( *m_EndY_Ctrl, m_Item->GetEnd().y, m_parent->GetInternalUnits() ); PutValueInLocalUnits( *m_ThicknessCtrl, m_Item->GetWidth(), m_parent->GetInternalUnits() ); int thickness; if( m_Item->GetLayer() == EDGE_N ) thickness = m_brdSettings.m_EdgeSegmentWidth; else thickness = m_brdSettings.m_DrawSegmentWidth; PutValueInLocalUnits( *m_DefaultThicknessCtrl, thickness, m_parent->GetInternalUnits() ); for( int layer=FIRST_NO_COPPER_LAYER; layer <= LAST_NO_COPPER_LAYER; ++layer ) { m_LayerSelectionCtrl->Append( m_parent->GetBoard()->GetLayerName( layer ) ); } int layer = m_Item->GetLayer(); // Control: if ( layer < FIRST_NO_COPPER_LAYER ) layer = FIRST_NO_COPPER_LAYER; if ( layer > LAST_NO_COPPER_LAYER ) layer = LAST_NO_COPPER_LAYER; m_LayerSelectionCtrl->SetSelection( layer - FIRST_NO_COPPER_LAYER ); }
int genPlacementRoutingMatrix( BOARD* aBrd, EDA_MSG_PANEL* messagePanel ) { wxString msg; RoutingMatrix.UnInitRoutingMatrix(); EDA_RECT bbox = aBrd->ComputeBoundingBox( true ); if( bbox.GetWidth() == 0 || bbox.GetHeight() == 0 ) { DisplayError( NULL, _( "No PCB edge found, unknown board size!" ) ); return 0; } RoutingMatrix.ComputeMatrixSize( aBrd, true ); int nbCells = RoutingMatrix.m_Ncols * RoutingMatrix.m_Nrows; messagePanel->EraseMsgBox(); msg.Printf( wxT( "%d" ), RoutingMatrix.m_Ncols ); messagePanel->SetMessage( 1, _( "Cols" ), msg, GREEN ); msg.Printf( wxT( "%d" ), RoutingMatrix.m_Nrows ); messagePanel->SetMessage( 7, _( "Lines" ), msg, GREEN ); msg.Printf( wxT( "%d" ), nbCells ); messagePanel->SetMessage( 14, _( "Cells." ), msg, YELLOW ); // Choose the number of board sides. RoutingMatrix.m_RoutingLayersCount = 2; RoutingMatrix.InitRoutingMatrix(); // Display memory usage. msg.Printf( wxT( "%d" ), RoutingMatrix.m_MemSize / 1024 ); messagePanel->SetMessage( 24, wxT( "Mem(Kb)" ), msg, CYAN ); g_Route_Layer_BOTTOM = LAYER_N_FRONT; if( RoutingMatrix.m_RoutingLayersCount > 1 ) g_Route_Layer_BOTTOM = LAYER_N_BACK; g_Route_Layer_TOP = LAYER_N_FRONT; // Place the edge layer segments TRACK TmpSegm( NULL ); TmpSegm.SetLayer( UNDEFINED_LAYER ); TmpSegm.SetNet( -1 ); TmpSegm.SetWidth( RoutingMatrix.m_GridRouting / 2 ); EDA_ITEM* PtStruct = aBrd->m_Drawings; for( ; PtStruct != NULL; PtStruct = PtStruct->Next() ) { DRAWSEGMENT* DrawSegm; switch( PtStruct->Type() ) { case PCB_LINE_T: DrawSegm = (DRAWSEGMENT*) PtStruct; if( DrawSegm->GetLayer() != EDGE_N ) break; TmpSegm.SetStart( DrawSegm->GetStart() ); TmpSegm.SetEnd( DrawSegm->GetEnd() ); TmpSegm.SetShape( DrawSegm->GetShape() ); TmpSegm.m_Param = DrawSegm->GetAngle(); TraceSegmentPcb( &TmpSegm, HOLE | CELL_is_EDGE, RoutingMatrix.m_GridRouting, WRITE_CELL ); break; case PCB_TEXT_T: default: break; } } // Mark cells of the routing matrix to CELL_is_ZONE // (i.e. availlable cell to place a module ) // Init a starting point of attachment to the area. RoutingMatrix.OrCell( RoutingMatrix.m_Nrows / 2, RoutingMatrix.m_Ncols / 2, BOTTOM, CELL_is_ZONE ); // find and mark all other availlable cells: for( int ii = 1; ii != 0; ) ii = propagate(); // Initialize top layer. to the same value as the bottom layer if( RoutingMatrix.m_BoardSide[TOP] ) memcpy( RoutingMatrix.m_BoardSide[TOP], RoutingMatrix.m_BoardSide[BOTTOM], nbCells * sizeof(MATRIX_CELL) ); return 1; }
void POINT_EDITOR::addCorner( const VECTOR2I& aBreakPoint ) { EDA_ITEM* item = m_editPoints->GetParent(); const SELECTION& selection = m_selectionTool->GetSelection(); if( item->Type() == PCB_ZONE_AREA_T ) { getEditFrame<PCB_BASE_FRAME>()->OnModify(); getEditFrame<PCB_BASE_FRAME>()->SaveCopyInUndoList( selection.items, UR_CHANGED ); ZONE_CONTAINER* zone = static_cast<ZONE_CONTAINER*>( item ); CPolyLine* outline = zone->Outline(); // Handle the last segment, so other segments can be easily handled in a loop unsigned int nearestIdx = outline->GetCornersCount() - 1, nextNearestIdx = 0; SEG side( VECTOR2I( outline->GetPos( nearestIdx ) ), VECTOR2I( outline->GetPos( nextNearestIdx ) ) ); unsigned int nearestDist = side.Distance( aBreakPoint ); for( int i = 0; i < outline->GetCornersCount() - 1; ++i ) { side = SEG( VECTOR2I( outline->GetPos( i ) ), VECTOR2I( outline->GetPos( i + 1 ) ) ); unsigned int distance = side.Distance( aBreakPoint ); if( distance < nearestDist ) { nearestDist = distance; nearestIdx = i; nextNearestIdx = i + 1; } } // Find the point on the closest segment VECTOR2I sideOrigin( outline->GetPos( nearestIdx ) ); VECTOR2I sideEnd( outline->GetPos( nextNearestIdx ) ); SEG nearestSide( sideOrigin, sideEnd ); VECTOR2I nearestPoint = nearestSide.NearestPoint( aBreakPoint ); // Do not add points that have the same coordinates as ones that already belong to polygon // instead, add a point in the middle of the side if( nearestPoint == sideOrigin || nearestPoint == sideEnd ) nearestPoint = ( sideOrigin + sideEnd ) / 2; outline->InsertCorner( nearestIdx, nearestPoint.x, nearestPoint.y ); } else if( item->Type() == PCB_LINE_T || item->Type() == PCB_MODULE_EDGE_T ) { bool moduleEdge = item->Type() == PCB_MODULE_EDGE_T; PCB_BASE_FRAME* frame = getEditFrame<PCB_BASE_FRAME>(); frame->OnModify(); if( moduleEdge ) frame->SaveCopyInUndoList( getModel<BOARD>()->m_Modules, UR_MODEDIT ); else frame->SaveCopyInUndoList( selection.items, UR_CHANGED ); DRAWSEGMENT* segment = static_cast<DRAWSEGMENT*>( item ); if( segment->GetShape() == S_SEGMENT ) { SEG seg( segment->GetStart(), segment->GetEnd() ); VECTOR2I nearestPoint = seg.NearestPoint( aBreakPoint ); // Move the end of the line to the break point.. segment->SetEnd( wxPoint( nearestPoint.x, nearestPoint.y ) ); // and add another one starting from the break point DRAWSEGMENT* newSegment; if( moduleEdge ) { EDGE_MODULE* edge = static_cast<EDGE_MODULE*>( segment ); assert( segment->GetParent()->Type() == PCB_MODULE_T ); newSegment = new EDGE_MODULE( *edge ); edge->SetLocalCoord(); } else { newSegment = new DRAWSEGMENT( *segment ); } newSegment->ClearSelected(); newSegment->SetStart( wxPoint( nearestPoint.x, nearestPoint.y ) ); newSegment->SetEnd( wxPoint( seg.B.x, seg.B.y ) ); if( moduleEdge ) { static_cast<EDGE_MODULE*>( newSegment )->SetLocalCoord(); getModel<BOARD>()->m_Modules->Add( newSegment ); } else { getModel<BOARD>()->Add( newSegment ); } getView()->Add( newSegment ); } } }
/** * Function PlaceCells * Initialize the matrix routing by setting obstacles for each occupied cell * a cell set to HOLE is an obstacle for tracks and vias * a cell set to VIA_IMPOSSIBLE is an obstacle for vias only. * a cell set to CELL_is_EDGE is a frontier. * Tracks and vias having the same net code as net_code are skipped * (htey do not are obstacles) * * For single-sided Routing 1: * BOTTOM side is used, and Route_Layer_BOTTOM = Route_Layer_TOP * * If flag == FORCE_PADS: all pads will be put in matrix as obstacles. */ void PlaceCells( BOARD* aPcb, int net_code, int flag ) { int ux0 = 0, uy0 = 0, ux1, uy1, dx, dy; int marge, via_marge; LAYER_MSK layerMask; // use the default NETCLASS? NETCLASS* nc = aPcb->m_NetClasses.GetDefault(); int trackWidth = nc->GetTrackWidth(); int clearance = nc->GetClearance(); int viaSize = nc->GetViaDiameter(); marge = clearance + (trackWidth / 2); via_marge = clearance + (viaSize / 2); // Place PADS on matrix routing: for( unsigned i = 0; i < aPcb->GetPadCount(); ++i ) { D_PAD* pad = aPcb->GetPad( i ); if( net_code != pad->GetNet() || (flag & FORCE_PADS) ) { ::PlacePad( pad, HOLE, marge, WRITE_CELL ); } ::PlacePad( pad, VIA_IMPOSSIBLE, via_marge, WRITE_OR_CELL ); } // Place outlines of modules on matrix routing, if they are on a copper layer // or on the edge layer TRACK tmpSegm( NULL ); // A dummy track used to create segments. for( MODULE* module = aPcb->m_Modules; module; module = module->Next() ) { for( BOARD_ITEM* item = module->GraphicalItems(); item; item = item->Next() ) { switch( item->Type() ) { case PCB_MODULE_EDGE_T: { EDGE_MODULE* edge = (EDGE_MODULE*) item; tmpSegm.SetLayer( edge->GetLayer() ); if( tmpSegm.GetLayer() == EDGE_N ) tmpSegm.SetLayer( UNDEFINED_LAYER ); tmpSegm.SetStart( edge->GetStart() ); tmpSegm.SetEnd( edge->GetEnd() ); tmpSegm.SetShape( edge->GetShape() ); tmpSegm.SetWidth( edge->GetWidth() ); tmpSegm.m_Param = edge->GetAngle(); tmpSegm.SetNet( -1 ); TraceSegmentPcb( &tmpSegm, HOLE, marge, WRITE_CELL ); TraceSegmentPcb( &tmpSegm, VIA_IMPOSSIBLE, via_marge, WRITE_OR_CELL ); } break; default: break; } } } // Place board outlines and texts on copper layers: for( BOARD_ITEM* item = aPcb->m_Drawings; item; item = item->Next() ) { switch( item->Type() ) { case PCB_LINE_T: { DRAWSEGMENT* DrawSegm; int type_cell = HOLE; DrawSegm = (DRAWSEGMENT*) item; tmpSegm.SetLayer( DrawSegm->GetLayer() ); if( DrawSegm->GetLayer() == EDGE_N ) { tmpSegm.SetLayer( UNDEFINED_LAYER ); type_cell |= CELL_is_EDGE; } tmpSegm.SetStart( DrawSegm->GetStart() ); tmpSegm.SetEnd( DrawSegm->GetEnd() ); tmpSegm.SetShape( DrawSegm->GetShape() ); tmpSegm.SetWidth( DrawSegm->GetWidth() ); tmpSegm.m_Param = DrawSegm->GetAngle(); tmpSegm.SetNet( -1 ); TraceSegmentPcb( &tmpSegm, type_cell, marge, WRITE_CELL ); } break; case PCB_TEXT_T: { TEXTE_PCB* PtText; PtText = (TEXTE_PCB*) item; if( PtText->GetText().Length() == 0 ) break; EDA_RECT textbox = PtText->GetTextBox( -1 ); ux0 = textbox.GetX(); uy0 = textbox.GetY(); dx = textbox.GetWidth(); dy = textbox.GetHeight(); /* Put bounding box (rectangle) on matrix */ dx /= 2; dy /= 2; ux1 = ux0 + dx; uy1 = uy0 + dy; ux0 -= dx; uy0 -= dy; layerMask = GetLayerMask( PtText->GetLayer() ); TraceFilledRectangle( ux0 - marge, uy0 - marge, ux1 + marge, uy1 + marge, PtText->GetOrientation(), layerMask, HOLE, WRITE_CELL ); TraceFilledRectangle( ux0 - via_marge, uy0 - via_marge, ux1 + via_marge, uy1 + via_marge, PtText->GetOrientation(), layerMask, VIA_IMPOSSIBLE, WRITE_OR_CELL ); } break; default: break; } } /* Put tracks and vias on matrix */ for( TRACK* track = aPcb->m_Track; track; track = track->Next() ) { if( net_code == track->GetNet() ) continue; TraceSegmentPcb( track, HOLE, marge, WRITE_CELL ); TraceSegmentPcb( track, VIA_IMPOSSIBLE, via_marge, WRITE_OR_CELL ); } }
void GRID_HELPER::computeAnchors( BOARD_ITEM* aItem, const VECTOR2I& aRefPos ) { VECTOR2I origin; switch( aItem->Type() ) { case PCB_MODULE_T: { MODULE* mod = static_cast<MODULE*>( aItem ); addAnchor( mod->GetPosition(), ORIGIN | SNAPPABLE, mod ); for( D_PAD* pad = mod->Pads(); pad; pad = pad->Next() ) addAnchor( pad->GetPosition(), CORNER | SNAPPABLE, pad ); break; } case PCB_PAD_T: { D_PAD* pad = static_cast<D_PAD*>( aItem ); addAnchor( pad->GetPosition(), CORNER | SNAPPABLE, pad ); break; } case PCB_MODULE_EDGE_T: case PCB_LINE_T: { DRAWSEGMENT* dseg = static_cast<DRAWSEGMENT*>( aItem ); VECTOR2I start = dseg->GetStart(); VECTOR2I end = dseg->GetEnd(); //LAYER_ID layer = dseg->GetLayer(); switch( dseg->GetShape() ) { case S_CIRCLE: { int r = ( start - end ).EuclideanNorm(); addAnchor( start, ORIGIN | SNAPPABLE, dseg ); addAnchor( start + VECTOR2I( -r, 0 ), OUTLINE | SNAPPABLE, dseg ); addAnchor( start + VECTOR2I( r, 0 ), OUTLINE | SNAPPABLE, dseg ); addAnchor( start + VECTOR2I( 0, -r ), OUTLINE | SNAPPABLE, dseg ); addAnchor( start + VECTOR2I( 0, r ), OUTLINE | SNAPPABLE, dseg ); break; } case S_ARC: { origin = dseg->GetCenter(); addAnchor( dseg->GetArcStart(), CORNER | SNAPPABLE, dseg ); addAnchor( dseg->GetArcEnd(), CORNER | SNAPPABLE, dseg ); addAnchor( origin, ORIGIN | SNAPPABLE, dseg ); break; } case S_SEGMENT: { origin.x = start.x + ( start.x - end.x ) / 2; origin.y = start.y + ( start.y - end.y ) / 2; addAnchor( start, CORNER | SNAPPABLE, dseg ); addAnchor( end, CORNER | SNAPPABLE, dseg ); addAnchor( origin, ORIGIN, dseg ); break; } default: { origin = dseg->GetStart(); addAnchor( origin, ORIGIN | SNAPPABLE, dseg ); break; } } break; } case PCB_TRACE_T: { TRACK* track = static_cast<TRACK*>( aItem ); VECTOR2I start = track->GetStart(); VECTOR2I end = track->GetEnd(); origin.x = start.x + ( start.x - end.x ) / 2; origin.y = start.y + ( start.y - end.y ) / 2; addAnchor( start, CORNER | SNAPPABLE, track ); addAnchor( end, CORNER | SNAPPABLE, track ); addAnchor( origin, ORIGIN, track); break; } case PCB_VIA_T: addAnchor( aItem->GetPosition(), CORNER | SNAPPABLE, aItem ); break; case PCB_ZONE_AREA_T: { const CPolyLine* outline = static_cast<const ZONE_CONTAINER*>( aItem )->Outline(); int cornersCount = outline->GetCornersCount(); SHAPE_LINE_CHAIN lc; lc.SetClosed( true ); for( int i = 0; i < cornersCount; ++i ) { const VECTOR2I p ( outline->GetPos( i ) ); addAnchor( p, CORNER, aItem ); lc.Append( p ); } addAnchor( lc.NearestPoint( aRefPos ), OUTLINE, aItem ); break; } case PCB_MODULE_TEXT_T: case PCB_TEXT_T: addAnchor( aItem->GetPosition(), ORIGIN, aItem ); default: break; } }
bool DIALOG_GRAPHIC_ITEM_PROPERTIES::TransferDataToWindow() { // Set unit symbol wxStaticText* texts_unit[] = { m_StartPointXUnit, m_StartPointYUnit, m_EndPointXUnit, m_EndPointYUnit, m_ThicknessTextUnit, m_DefaulThicknessTextUnit, }; for( size_t ii = 0; ii < DIM( texts_unit ); ii++ ) { texts_unit[ii]->SetLabel( GetAbbreviatedUnitsLabel() ); } wxString msg; // Change texts according to the segment shape: switch( m_item->GetShape() ) { case S_CIRCLE: SetTitle( _( "Circle Properties" ) ); m_StartPointXLabel->SetLabel( _( "Center X:" ) ); m_StartPointYLabel->SetLabel( _( "Center Y:" ) ); m_EndPointXLabel->SetLabel( _( "Point X:" ) ); m_EndPointYLabel->SetLabel( _( "Point Y:" ) ); m_AngleText->Show( false ); m_AngleCtrl->Show( false ); m_AngleUnit->Show( false ); break; case S_ARC: SetTitle( _( "Arc Properties" ) ); m_StartPointXLabel->SetLabel( _( "Center X:" ) ); m_StartPointYLabel->SetLabel( _( "Center Y:" ) ); m_EndPointXLabel->SetLabel( _( "Start Point X:" ) ); m_EndPointYLabel->SetLabel( _( "Start Point Y:" ) ); m_AngleValue = m_item->GetAngle() / 10.0; break; case S_SEGMENT: SetTitle( _( "Line Segment Properties" ) ); // Fall through. default: m_AngleText->Show( false ); m_AngleCtrl->Show( false ); m_AngleUnit->Show( false ); break; } PutValueInLocalUnits( *m_Center_StartXCtrl, m_item->GetStart().x ); PutValueInLocalUnits( *m_Center_StartYCtrl, m_item->GetStart().y ); PutValueInLocalUnits( *m_EndX_Radius_Ctrl, m_item->GetEnd().x ); PutValueInLocalUnits( *m_EndY_Ctrl, m_item->GetEnd().y ); PutValueInLocalUnits( *m_ThicknessCtrl, m_item->GetWidth() ); int thickness; if( m_item->GetLayer() == Edge_Cuts ) thickness = m_brdSettings.m_EdgeSegmentWidth; else thickness = m_brdSettings.m_DrawSegmentWidth; PutValueInLocalUnits( *m_DefaultThicknessCtrl, thickness ); // Configure the layers list selector m_LayerSelectionCtrl->SetLayersHotkeys( false ); m_LayerSelectionCtrl->SetLayerSet( LSET::AllCuMask() ); m_LayerSelectionCtrl->SetBoardFrame( m_parent ); m_LayerSelectionCtrl->Resync(); if( m_LayerSelectionCtrl->SetLayerSelection( m_item->GetLayer() ) < 0 ) { wxMessageBox( _( "This item was on an unknown layer.\n" "It has been moved to the drawings layer. Please fix it." ) ); m_LayerSelectionCtrl->SetLayerSelection( Dwgs_User ); } return DIALOG_GRAPHIC_ITEM_PROPERTIES_BASE::TransferDataToWindow(); }
int DRAWING_TOOL::PlaceDXF( const TOOL_EVENT& aEvent ) { if( !m_frame->GetModel() ) return 0; DIALOG_DXF_IMPORT dlg( m_frame ); int dlgResult = dlg.ShowModal(); const std::list<BOARD_ITEM*>& list = dlg.GetImportedItems(); if( dlgResult != wxID_OK || list.empty() ) return 0; VECTOR2I cursorPos = m_controls->GetCursorPosition(); VECTOR2I delta = cursorPos - list.front()->GetPosition(); // Add a VIEW_GROUP that serves as a preview for the new item SELECTION preview( m_view ); BOARD_COMMIT commit( m_frame ); // Build the undo list & add items to the current view for( auto item : list ) { assert( item->Type() == PCB_LINE_T || item->Type() == PCB_TEXT_T ); preview.Add( item ); } BOARD_ITEM* firstItem = preview.Front(); m_view->Add( &preview ); m_toolMgr->RunAction( COMMON_ACTIONS::selectionClear, true ); m_controls->ShowCursor( true ); m_controls->SetSnapping( true ); SCOPED_DRAW_MODE scopedDrawMode( m_mode, MODE::DXF ); Activate(); // Main loop: keep receiving events while( OPT_TOOL_EVENT evt = Wait() ) { cursorPos = m_controls->GetCursorPosition(); if( evt->IsMotion() ) { delta = cursorPos - firstItem->GetPosition(); for( auto item : preview ) item->Move( wxPoint( delta.x, delta.y ) ); m_view->Update( &preview ); } else if( evt->Category() == TC_COMMAND ) { // TODO it should be handled by EDIT_TOOL, so add items and select? if( evt->IsAction( &COMMON_ACTIONS::rotate ) ) { for( auto item : preview ) item->Rotate( wxPoint( cursorPos.x, cursorPos.y ), m_frame->GetRotationAngle() ); m_view->Update( &preview ); } else if( evt->IsAction( &COMMON_ACTIONS::flip ) ) { for( auto item : preview ) item->Flip( wxPoint( cursorPos.x, cursorPos.y ) ); m_view->Update( &preview ); } else if( evt->IsCancel() || evt->IsActivate() ) { preview.FreeItems(); break; } } else if ( evt->IsClick( BUT_RIGHT ) ) { showContextMenu(); } else if( evt->IsClick( BUT_LEFT ) ) { // Place the drawing BOARD_ITEM_CONTAINER* parent = m_frame->GetModel(); for( auto item : preview ) { if( m_editModules ) { // Modules use different types for the same things, // so we need to convert imported items to appropriate classes. BOARD_ITEM* converted = NULL; switch( item->Type() ) { case PCB_TEXT_T: { TEXTE_PCB* text = static_cast<TEXTE_PCB*>( item ); TEXTE_MODULE* textMod = new TEXTE_MODULE( (MODULE*) parent ); // Assignment operator also copies the item PCB_TEXT_T type, // so it cannot be added to a module which handles PCB_MODULE_TEXT_T textMod->SetPosition( text->GetPosition() ); textMod->SetText( text->GetText() ); textMod->SetSize( text->GetSize() ); textMod->SetThickness( text->GetThickness() ); textMod->SetOrientation( text->GetOrientation() ); textMod->SetTextPosition( text->GetTextPosition() ); textMod->SetSize( text->GetSize() ); textMod->SetMirrored( text->IsMirrored() ); textMod->SetAttributes( text->GetAttributes() ); textMod->SetItalic( text->IsItalic() ); textMod->SetBold( text->IsBold() ); textMod->SetHorizJustify( text->GetHorizJustify() ); textMod->SetVertJustify( text->GetVertJustify() ); textMod->SetMultilineAllowed( text->IsMultilineAllowed() ); converted = textMod; break; } case PCB_LINE_T: { DRAWSEGMENT* seg = static_cast<DRAWSEGMENT*>( item ); EDGE_MODULE* modSeg = new EDGE_MODULE( (MODULE*) parent ); // Assignment operator also copies the item PCB_LINE_T type, // so it cannot be added to a module which handles PCB_MODULE_EDGE_T modSeg->SetWidth( seg->GetWidth() ); modSeg->SetStart( seg->GetStart() ); modSeg->SetEnd( seg->GetEnd() ); modSeg->SetAngle( seg->GetAngle() ); modSeg->SetShape( seg->GetShape() ); modSeg->SetType( seg->GetType() ); modSeg->SetBezControl1( seg->GetBezControl1() ); modSeg->SetBezControl2( seg->GetBezControl2() ); modSeg->SetBezierPoints( seg->GetBezierPoints() ); modSeg->SetPolyPoints( seg->GetPolyPoints() ); converted = modSeg; break; } default: assert( false ); break; } if( converted ) converted->SetLayer( item->GetLayer() ); delete item; item = converted; } if( item ) commit.Add( item ); } commit.Push( _( "Place a DXF drawing" ) ); break; } } preview.Clear(); m_controls->ShowCursor( false ); m_controls->SetSnapping( false ); m_controls->SetAutoPan( false ); m_controls->CaptureCursor( false ); m_view->Remove( &preview ); return 0; }
void DIALOG_GRAPHIC_ITEM_PROPERTIES::initDlg() { m_StandardButtonsSizerOK->SetDefault(); // Set unit symbol wxStaticText* texts_unit[] = { m_StartPointXUnit, m_StartPointYUnit, m_EndPointXUnit, m_EndPointYUnit, m_ThicknessTextUnit, m_DefaulThicknessTextUnit, NULL }; for( int ii = 0; ; ii++ ) { if( texts_unit[ii] == NULL ) break; texts_unit[ii]->SetLabel( GetAbbreviatedUnitsLabel() ); } wxString msg; // Change texts according to the segment shape: switch( m_item->GetShape() ) { case S_CIRCLE: SetTitle( _( "Circle Properties" ) ); m_StartPointXLabel->SetLabel( _( "Center X" ) ); m_StartPointYLabel->SetLabel( _( "Center Y" ) ); m_EndPointXLabel->SetLabel( _( "Point X" ) ); m_EndPointYLabel->SetLabel( _( "Point Y" ) ); m_Angle_Text->Show( false ); m_Angle_Ctrl->Show( false ); m_AngleUnit->Show( false ); break; case S_ARC: SetTitle( _( "Arc Properties" ) ); m_StartPointXLabel->SetLabel( _( "Center X" ) ); m_StartPointYLabel->SetLabel( _( "Center Y" ) ); m_EndPointXLabel->SetLabel( _( "Start Point X" ) ); m_EndPointYLabel->SetLabel( _( "Start Point Y" ) ); // Here the angle is a double, but the UI is still working with integers. msg << int( m_item->GetAngle() ); m_Angle_Ctrl->SetValue( msg ); break; case S_SEGMENT: SetTitle( _( "Line Segment Properties" ) ); // Fall through. default: m_Angle_Text->Show( false ); m_Angle_Ctrl->Show( false ); m_AngleUnit->Show( false ); break; } PutValueInLocalUnits( *m_Center_StartXCtrl, m_item->GetStart().x ); PutValueInLocalUnits( *m_Center_StartYCtrl, m_item->GetStart().y ); PutValueInLocalUnits( *m_EndX_Radius_Ctrl, m_item->GetEnd().x ); PutValueInLocalUnits( *m_EndY_Ctrl, m_item->GetEnd().y ); PutValueInLocalUnits( *m_ThicknessCtrl, m_item->GetWidth() ); int thickness; if( m_item->GetLayer() == Edge_Cuts ) thickness = m_brdSettings.m_EdgeSegmentWidth; else thickness = m_brdSettings.m_DrawSegmentWidth; PutValueInLocalUnits( *m_DefaultThicknessCtrl, thickness ); // Configure the layers list selector m_LayerSelectionCtrl->SetLayersHotkeys( false ); m_LayerSelectionCtrl->SetLayerSet( LSET::AllCuMask() ); m_LayerSelectionCtrl->SetBoardFrame( m_parent ); m_LayerSelectionCtrl->Resync(); if( m_LayerSelectionCtrl->SetLayerSelection( m_item->GetLayer() ) < 0 ) { wxMessageBox( _( "This item was on an unknown layer.\n" "It has been moved to the drawings layer. Please fix it." ) ); m_LayerSelectionCtrl->SetLayerSelection( Dwgs_User ); } }
/** * Function ConvertOutlineToPolygon * build a polygon (with holes) from a DRAWSEGMENT list, which is expected to be * a outline, therefore a closed main outline with perhaps closed inner outlines. * These closed inner outlines are considered as holes in the main outline * @param aSegList the initial list of drawsegments (only lines, circles and arcs). * @param aPolygons will contain the complex polygon. * @param aTolerance is the max distance between points that is still accepted as connected (internal units) * @param aErrorText is a wxString to return error message. * @param aErrorLocation is the optional position of the error in the outline */ bool ConvertOutlineToPolygon( std::vector<DRAWSEGMENT*>& aSegList, SHAPE_POLY_SET& aPolygons, wxString* aErrorText, unsigned int aTolerance, wxPoint* aErrorLocation ) { if( aSegList.size() == 0 ) return true; wxString msg; // Make a working copy of aSegList, because the list is modified during calculations std::vector< DRAWSEGMENT* > segList = aSegList; DRAWSEGMENT* graphic; wxPoint prevPt; // Find edge point with minimum x, this should be in the outer polygon // which will define the perimeter Edge.Cuts polygon. wxPoint xmin = wxPoint( INT_MAX, 0 ); int xmini = 0; for( size_t i = 0; i < segList.size(); i++ ) { graphic = (DRAWSEGMENT*) segList[i]; switch( graphic->GetShape() ) { case S_SEGMENT: { if( graphic->GetStart().x < xmin.x ) { xmin = graphic->GetStart(); xmini = i; } if( graphic->GetEnd().x < xmin.x ) { xmin = graphic->GetEnd(); xmini = i; } } break; case S_ARC: // Freerouter does not yet understand arcs, so approximate // an arc with a series of short lines and put those // line segments into the !same! PATH. { wxPoint pstart = graphic->GetArcStart(); wxPoint center = graphic->GetCenter(); double angle = -graphic->GetAngle(); double radius = graphic->GetRadius(); int steps = GetArcToSegmentCount( radius, ARC_LOW_DEF, angle / 10.0 ); wxPoint pt; for( int step = 1; step<=steps; ++step ) { double rotation = ( angle * step ) / steps; pt = pstart; RotatePoint( &pt, center, rotation ); if( pt.x < xmin.x ) { xmin = pt; xmini = i; } } } break; case S_CIRCLE: { wxPoint pt = graphic->GetCenter(); // pt has minimum x point pt.x -= graphic->GetRadius(); // when the radius <= 0, this is a mal-formed circle. Skip it if( graphic->GetRadius() > 0 && pt.x < xmin.x ) { xmin = pt; xmini = i; } } break; case S_CURVE: { graphic->RebuildBezierToSegmentsPointsList( graphic->GetWidth() ); for( unsigned int jj = 0; jj < graphic->GetBezierPoints().size(); jj++ ) { wxPoint pt = graphic->GetBezierPoints()[jj]; if( pt.x < xmin.x ) { xmin = pt; xmini = i; } } } break; case S_POLYGON: { const auto poly = graphic->GetPolyShape(); MODULE* module = aSegList[0]->GetParentModule(); double orientation = module ? module->GetOrientation() : 0.0; VECTOR2I offset = module ? module->GetPosition() : VECTOR2I( 0, 0 ); for( auto iter = poly.CIterate(); iter; iter++ ) { auto pt = *iter; RotatePoint( pt, orientation ); pt += offset; if( pt.x < xmin.x ) { xmin.x = pt.x; xmin.y = pt.y; xmini = i; } } } break; default: break; } } // Grab the left most point, assume its on the board's perimeter, and see if we // can put enough graphics together by matching endpoints to formulate a cohesive // polygon. graphic = (DRAWSEGMENT*) segList[xmini]; // The first DRAWSEGMENT is in 'graphic', ok to remove it from 'items' segList.erase( segList.begin() + xmini ); // Output the Edge.Cuts perimeter as circle or polygon. if( graphic->GetShape() == S_CIRCLE ) { int steps = GetArcToSegmentCount( graphic->GetRadius(), ARC_LOW_DEF, 360.0 ); TransformCircleToPolygon( aPolygons, graphic->GetCenter(), graphic->GetRadius(), steps ); } else if( graphic->GetShape() == S_POLYGON ) { MODULE* module = graphic->GetParentModule(); // NULL for items not in footprints double orientation = module ? module->GetOrientation() : 0.0; VECTOR2I offset = module ? module->GetPosition() : VECTOR2I( 0, 0 ); aPolygons.NewOutline(); for( auto it = graphic->GetPolyShape().CIterate( 0 ); it; it++ ) { auto pt = *it; RotatePoint( pt, orientation ); pt += offset; aPolygons.Append( pt ); } } else { // Polygon start point. Arbitrarily chosen end of the // segment and build the poly from here. wxPoint startPt = wxPoint( graphic->GetEnd() ); prevPt = graphic->GetEnd(); aPolygons.NewOutline(); aPolygons.Append( prevPt ); // Do not append the other end point yet of this 'graphic', this first // 'graphic' might be an arc or a curve. for(;;) { switch( graphic->GetShape() ) { case S_SEGMENT: { wxPoint nextPt; // Use the line segment end point furthest away from // prevPt as we assume the other end to be ON prevPt or // very close to it. if( close_st( prevPt, graphic->GetStart(), graphic->GetEnd() ) ) nextPt = graphic->GetEnd(); else nextPt = graphic->GetStart(); aPolygons.Append( nextPt ); prevPt = nextPt; } break; case S_ARC: // We do not support arcs in polygons, so approximate // an arc with a series of short lines and put those // line segments into the !same! PATH. { wxPoint pstart = graphic->GetArcStart(); wxPoint pend = graphic->GetArcEnd(); wxPoint pcenter = graphic->GetCenter(); double angle = -graphic->GetAngle(); double radius = graphic->GetRadius(); int steps = GetArcToSegmentCount( radius, ARC_LOW_DEF, angle / 10.0 ); if( !close_enough( prevPt, pstart, aTolerance ) ) { wxASSERT( close_enough( prevPt, graphic->GetArcEnd(), aTolerance ) ); angle = -angle; std::swap( pstart, pend ); } wxPoint nextPt; for( int step = 1; step<=steps; ++step ) { double rotation = ( angle * step ) / steps; nextPt = pstart; RotatePoint( &nextPt, pcenter, rotation ); aPolygons.Append( nextPt ); } prevPt = nextPt; } break; case S_CURVE: // We do not support Bezier curves in polygons, so approximate // with a series of short lines and put those // line segments into the !same! PATH. { wxPoint nextPt; bool reverse = false; // Use the end point furthest away from // prevPt as we assume the other end to be ON prevPt or // very close to it. if( close_st( prevPt, graphic->GetStart(), graphic->GetEnd() ) ) nextPt = graphic->GetEnd(); else { nextPt = graphic->GetStart(); reverse = true; } if( reverse ) { for( int jj = graphic->GetBezierPoints().size()-1; jj >= 0; jj-- ) aPolygons.Append( graphic->GetBezierPoints()[jj] ); } else { for( size_t jj = 0; jj < graphic->GetBezierPoints().size(); jj++ ) aPolygons.Append( graphic->GetBezierPoints()[jj] ); } prevPt = nextPt; } break; default: if( aErrorText ) { msg.Printf( "Unsupported DRAWSEGMENT type %s.", BOARD_ITEM::ShowShape( graphic->GetShape() ) ); *aErrorText << msg << "\n"; } if( aErrorLocation ) *aErrorLocation = graphic->GetPosition(); return false; } // Get next closest segment. graphic = findPoint( prevPt, segList, aTolerance ); // If there are no more close segments, check if the board // outline polygon can be closed. if( !graphic ) { if( close_enough( startPt, prevPt, aTolerance ) ) { // Close the polygon back to start point // aPolygons.Append( startPt ); // not needed } else { if( aErrorText ) { msg.Printf( _( "Unable to find segment with an endpoint of (%s, %s)." ), StringFromValue( MILLIMETRES, prevPt.x, true ), StringFromValue( MILLIMETRES, prevPt.y, true ) ); *aErrorText << msg << "\n"; } if( aErrorLocation ) *aErrorLocation = prevPt; return false; } break; } } } while( segList.size() ) { // emit a signal layers keepout for every interior polygon left... int hole = aPolygons.NewHole(); graphic = (DRAWSEGMENT*) segList[0]; segList.erase( segList.begin() ); // Both circles and polygons on the edge cuts layer are closed items that // do not connect to other elements, so we process them independently if( graphic->GetShape() == S_POLYGON ) { MODULE* module = graphic->GetParentModule(); // NULL for items not in footprints double orientation = module ? module->GetOrientation() : 0.0; VECTOR2I offset = module ? module->GetPosition() : VECTOR2I( 0, 0 ); for( auto it = graphic->GetPolyShape().CIterate(); it; it++ ) { auto val = *it; RotatePoint( val, orientation ); val += offset; aPolygons.Append( val, -1, hole ); } } else if( graphic->GetShape() == S_CIRCLE ) { // make a circle by segments; wxPoint center = graphic->GetCenter(); double angle = 3600.0; wxPoint start = center; int radius = graphic->GetRadius(); int steps = GetArcToSegmentCount( radius, ARC_LOW_DEF, 360.0 ); wxPoint nextPt; start.x += radius; for( int step = 0; step < steps; ++step ) { double rotation = ( angle * step ) / steps; nextPt = start; RotatePoint( &nextPt.x, &nextPt.y, center.x, center.y, rotation ); aPolygons.Append( nextPt, -1, hole ); } } else { // Polygon start point. Arbitrarily chosen end of the // segment and build the poly from here. wxPoint startPt( graphic->GetEnd() ); prevPt = graphic->GetEnd(); aPolygons.Append( prevPt, -1, hole ); // do not append the other end point yet, this first 'graphic' might be an arc for(;;) { switch( graphic->GetShape() ) { case S_SEGMENT: { wxPoint nextPt; // Use the line segment end point furthest away from // prevPt as we assume the other end to be ON prevPt or // very close to it. if( close_st( prevPt, graphic->GetStart(), graphic->GetEnd() ) ) { nextPt = graphic->GetEnd(); } else { nextPt = graphic->GetStart(); } prevPt = nextPt; aPolygons.Append( prevPt, -1, hole ); } break; case S_ARC: // Freerouter does not yet understand arcs, so approximate // an arc with a series of short lines and put those // line segments into the !same! PATH. { wxPoint pstart = graphic->GetArcStart(); wxPoint pend = graphic->GetArcEnd(); wxPoint pcenter = graphic->GetCenter(); double angle = -graphic->GetAngle(); int radius = graphic->GetRadius(); int steps = GetArcToSegmentCount( radius, ARC_LOW_DEF, angle / 10.0 ); if( !close_enough( prevPt, pstart, aTolerance ) ) { wxASSERT( close_enough( prevPt, graphic->GetArcEnd(), aTolerance ) ); angle = -angle; std::swap( pstart, pend ); } wxPoint nextPt; for( int step = 1; step <= steps; ++step ) { double rotation = ( angle * step ) / steps; nextPt = pstart; RotatePoint( &nextPt, pcenter, rotation ); aPolygons.Append( nextPt, -1, hole ); } prevPt = nextPt; } break; case S_CURVE: // We do not support Bezier curves in polygons, so approximate // with a series of short lines and put those // line segments into the !same! PATH. { wxPoint nextPt; bool reverse = false; // Use the end point furthest away from // prevPt as we assume the other end to be ON prevPt or // very close to it. if( close_st( prevPt, graphic->GetStart(), graphic->GetEnd() ) ) nextPt = graphic->GetEnd(); else { nextPt = graphic->GetStart(); reverse = true; } if( reverse ) { for( int jj = graphic->GetBezierPoints().size()-1; jj >= 0; jj-- ) aPolygons.Append( graphic->GetBezierPoints()[jj], -1, hole ); } else { for( size_t jj = 0; jj < graphic->GetBezierPoints().size(); jj++ ) aPolygons.Append( graphic->GetBezierPoints()[jj], -1, hole ); } prevPt = nextPt; } break; default: if( aErrorText ) { msg.Printf( "Unsupported DRAWSEGMENT type %s.", BOARD_ITEM::ShowShape( graphic->GetShape() ) ); *aErrorText << msg << "\n"; } if( aErrorLocation ) *aErrorLocation = graphic->GetPosition(); return false; } // Get next closest segment. graphic = findPoint( prevPt, segList, aTolerance ); // If there are no more close segments, check if polygon // can be closed. if( !graphic ) { if( close_enough( startPt, prevPt, aTolerance ) ) { // Close the polygon back to start point // aPolygons.Append( startPt, -1, hole ); // not needed } else { if( aErrorText ) { msg.Printf( _( "Unable to find segment with an endpoint of (%s, %s)." ), StringFromValue( MILLIMETRES, prevPt.x, true ), StringFromValue( MILLIMETRES, prevPt.y, true ) ); *aErrorText << msg << "\n"; } if( aErrorLocation ) *aErrorLocation = prevPt; return false; } break; } } } } return true; }
/** * Searches for a DRAWSEGMENT matching a given end point or start point in a list, and * if found, removes it from the TYPE_COLLECTOR and returns it, else returns NULL. * @param aPoint The starting or ending point to search for. * @param aList The list to remove from. * @param aLimit is the distance from \a aPoint that still constitutes a valid find. * @return DRAWSEGMENT* - The first DRAWSEGMENT that has a start or end point matching * aPoint, otherwise NULL if none. */ static DRAWSEGMENT* findPoint( const wxPoint& aPoint, std::vector< DRAWSEGMENT* >& aList, unsigned aLimit ) { unsigned min_d = INT_MAX; int ndx_min = 0; // find the point closest to aPoint and perhaps exactly matching aPoint. for( size_t i = 0; i < aList.size(); ++i ) { DRAWSEGMENT* graphic = aList[i]; unsigned d; switch( graphic->GetShape() ) { case S_ARC: if( aPoint == graphic->GetArcStart() || aPoint == graphic->GetArcEnd() ) { aList.erase( aList.begin() + i ); return graphic; } d = close_ness( aPoint, graphic->GetArcStart() ); if( d < min_d ) { min_d = d; ndx_min = i; } d = close_ness( aPoint, graphic->GetArcEnd() ); if( d < min_d ) { min_d = d; ndx_min = i; } break; default: if( aPoint == graphic->GetStart() || aPoint == graphic->GetEnd() ) { aList.erase( aList.begin() + i ); return graphic; } d = close_ness( aPoint, graphic->GetStart() ); if( d < min_d ) { min_d = d; ndx_min = i; } d = close_ness( aPoint, graphic->GetEnd() ); if( d < min_d ) { min_d = d; ndx_min = i; } } } if( min_d <= aLimit ) { DRAWSEGMENT* graphic = aList[ndx_min]; aList.erase( aList.begin() + ndx_min ); return graphic; } return NULL; }