/* Place module on Routing matrix. */ void genModuleOnRoutingMatrix( MODULE* Module ) { int ox, oy, fx, fy; int layerMask; D_PAD* Pad; EDA_RECT fpBBox = Module->GetBoundingBox(); fpBBox.Inflate( RoutingMatrix.m_GridRouting / 2 ); ox = fpBBox.GetX(); fx = fpBBox.GetRight(); oy = fpBBox.GetY(); fy = fpBBox.GetBottom(); if( ox < RoutingMatrix.m_BrdBox.GetX() ) ox = RoutingMatrix.m_BrdBox.GetX(); if( ox > RoutingMatrix.m_BrdBox.GetRight() ) ox = RoutingMatrix.m_BrdBox.GetRight(); if( fx < RoutingMatrix.m_BrdBox.GetX() ) fx = RoutingMatrix.m_BrdBox.GetX(); if( fx > RoutingMatrix.m_BrdBox.GetRight() ) fx = RoutingMatrix.m_BrdBox.GetRight(); if( oy < RoutingMatrix.m_BrdBox.GetY() ) oy = RoutingMatrix.m_BrdBox.GetY(); if( oy > RoutingMatrix.m_BrdBox.GetBottom() ) oy = RoutingMatrix.m_BrdBox.GetBottom(); if( fy < RoutingMatrix.m_BrdBox.GetY() ) fy = RoutingMatrix.m_BrdBox.GetY(); if( fy > RoutingMatrix.m_BrdBox.GetBottom() ) fy = RoutingMatrix.m_BrdBox.GetBottom(); layerMask = 0; if( Module->GetLayer() == LAYER_N_FRONT ) layerMask = LAYER_FRONT; if( Module->GetLayer() == LAYER_N_BACK ) layerMask = LAYER_BACK; TraceFilledRectangle( ox, oy, fx, fy, layerMask, CELL_is_MODULE, WRITE_OR_CELL ); // Trace pads + clearance areas. for( Pad = Module->Pads(); Pad != NULL; Pad = Pad->Next() ) { int margin = (RoutingMatrix.m_GridRouting / 2) + Pad->GetClearance(); ::PlacePad( Pad, CELL_is_MODULE, margin, WRITE_OR_CELL ); } // Trace clearance. int margin = ( RoutingMatrix.m_GridRouting * Module->GetPadCount() ) / GAIN; CreateKeepOutRectangle( ox, oy, fx, fy, margin, KEEP_OUT_MARGIN, layerMask ); }
const EDA_RECT DIMENSION::GetBoundingBox() const { EDA_RECT bBox; int xmin, xmax, ymin, ymax; bBox = m_Text.GetTextBox( -1 ); xmin = bBox.GetX(); xmax = bBox.GetRight(); ymin = bBox.GetY(); ymax = bBox.GetBottom(); xmin = std::min( xmin, m_crossBarO.x ); xmin = std::min( xmin, m_crossBarF.x ); ymin = std::min( ymin, m_crossBarO.y ); ymin = std::min( ymin, m_crossBarF.y ); xmax = std::max( xmax, m_crossBarO.x ); xmax = std::max( xmax, m_crossBarF.x ); ymax = std::max( ymax, m_crossBarO.y ); ymax = std::max( ymax, m_crossBarF.y ); xmin = std::min( xmin, m_featureLineGO.x ); xmin = std::min( xmin, m_featureLineGF.x ); ymin = std::min( ymin, m_featureLineGO.y ); ymin = std::min( ymin, m_featureLineGF.y ); xmax = std::max( xmax, m_featureLineGO.x ); xmax = std::max( xmax, m_featureLineGF.x ); ymax = std::max( ymax, m_featureLineGO.y ); ymax = std::max( ymax, m_featureLineGF.y ); xmin = std::min( xmin, m_featureLineDO.x ); xmin = std::min( xmin, m_featureLineDF.x ); ymin = std::min( ymin, m_featureLineDO.y ); ymin = std::min( ymin, m_featureLineDF.y ); xmax = std::max( xmax, m_featureLineDO.x ); xmax = std::max( xmax, m_featureLineDF.x ); ymax = std::max( ymax, m_featureLineDO.y ); ymax = std::max( ymax, m_featureLineDF.y ); bBox.SetX( xmin ); bBox.SetY( ymin ); bBox.SetWidth( xmax - xmin + 1 ); bBox.SetHeight( ymax - ymin + 1 ); bBox.Normalize(); return bBox; }
void EDA_DRAW_PANEL::RefreshDrawingRect( const EDA_RECT& aRect, bool aEraseBackground ) { INSTALL_UNBUFFERED_DC( dc, this ); wxRect rect = aRect; rect.x = dc.LogicalToDeviceX( rect.x ); rect.y = dc.LogicalToDeviceY( rect.y ); rect.width = dc.LogicalToDeviceXRel( rect.width ); rect.height = dc.LogicalToDeviceYRel( rect.height ); wxLogTrace( kicadTraceCoords, wxT( "Refresh area: drawing (%d, %d, %d, %d), device (%d, %d, %d, %d)" ), aRect.GetX(), aRect.GetY(), aRect.GetWidth(), aRect.GetHeight(), rect.x, rect.y, rect.width, rect.height ); RefreshRect( rect, aEraseBackground ); }
EDA_RECT EDA_TEXT::GetTextBox( int aLine, int aThickness, bool aInvertY ) const { EDA_RECT rect; wxPoint pos; wxArrayString strings; wxString text = GetShownText(); int thickness = ( aThickness < 0 ) ? m_Thickness : aThickness; int linecount = 1; if( m_MultilineAllowed ) { wxStringSplit( text, strings, '\n' ); if ( strings.GetCount() ) // GetCount() == 0 for void strings { if( aLine >= 0 && (aLine < (int)strings.GetCount()) ) text = strings.Item( aLine ); else text = strings.Item( 0 ); linecount = strings.GetCount(); } } // calculate the H and V size int dx = LenSize( text ); int dy = GetInterline( aThickness ); // Creates bounding box (rectangle) for an horizontal text wxSize textsize = wxSize( dx, dy ); if( aInvertY ) rect.SetOrigin( m_Pos.x, -m_Pos.y ); else rect.SetOrigin( m_Pos ); // extra dy interval for letters like j and y and ] int extra_dy = dy - m_Size.y; rect.Move( wxPoint( 0, -extra_dy / 2 ) ); // move origin by the half extra interval // for multiline texts and aLine < 0, merge all rectangles if( m_MultilineAllowed && aLine < 0 ) { for( unsigned ii = 1; ii < strings.GetCount(); ii++ ) { text = strings.Item( ii ); dx = LenSize( text ); textsize.x = std::max( textsize.x, dx ); textsize.y += dy; } } rect.SetSize( textsize ); /* Now, calculate the rect origin, according to text justification * At this point the rectangle origin is the text origin (m_Pos). * This is true only for left and top text justified texts (using top to bottom Y axis * orientation). and must be recalculated for others justifications * also, note the V justification is relative to the first line */ switch( m_HJustify ) { case GR_TEXT_HJUSTIFY_LEFT: if( m_Mirror ) rect.SetX( rect.GetX() - rect.GetWidth() ); break; case GR_TEXT_HJUSTIFY_CENTER: rect.SetX( rect.GetX() - (rect.GetWidth() / 2) ); break; case GR_TEXT_HJUSTIFY_RIGHT: if( !m_Mirror ) rect.SetX( rect.GetX() - rect.GetWidth() ); break; } dy = m_Size.y + thickness; switch( m_VJustify ) { case GR_TEXT_VJUSTIFY_TOP: break; case GR_TEXT_VJUSTIFY_CENTER: rect.SetY( rect.GetY() - ( dy / 2) ); break; case GR_TEXT_VJUSTIFY_BOTTOM: rect.SetY( rect.GetY() - dy ); break; } if( linecount > 1 ) { int yoffset; linecount -= 1; switch( m_VJustify ) { case GR_TEXT_VJUSTIFY_TOP: break; case GR_TEXT_VJUSTIFY_CENTER: yoffset = linecount * GetInterline() / 2; rect.SetY( rect.GetY() - yoffset ); break; case GR_TEXT_VJUSTIFY_BOTTOM: yoffset = linecount * GetInterline( aThickness ); rect.SetY( rect.GetY() - yoffset ); break; } } rect.Inflate( thickness / 2 ); rect.Normalize(); // Make h and v sizes always >= 0 return rect; }
void BOARD_PRINTOUT_CONTROLLER::DrawPage() { wxPoint offset; double userscale; EDA_RECT boardBoundingBox; EDA_RECT drawRect; wxDC* dc = GetDC(); BASE_SCREEN* screen = m_Parent->GetScreen(); bool printMirror = m_PrintParams.m_PrintMirror; wxSize pageSizeIU = m_Parent->GetPageSizeIU(); wxBusyCursor dummy; #if defined (PCBNEW) BOARD * brd = ((PCB_BASE_FRAME*) m_Parent)->GetBoard(); boardBoundingBox = brd->ComputeBoundingBox(); wxString titleblockFilename = brd->GetFileName(); #elif defined (GERBVIEW) boardBoundingBox = ((GERBVIEW_FRAME*) m_Parent)->GetGerberLayoutBoundingBox(); wxString titleblockFilename; // TODO see if we uses the gerber file name #else #error BOARD_PRINTOUT_CONTROLLER::DrawPage() works only for PCBNEW or GERBVIEW #endif // Use the page size as the drawing area when the board is shown or the user scale // is less than 1. if( m_PrintParams.PrintBorderAndTitleBlock() ) boardBoundingBox = EDA_RECT( wxPoint( 0, 0 ), pageSizeIU ); wxLogTrace( tracePrinting, wxT( "Drawing bounding box: x=%d, y=%d, w=%d, h=%d" ), boardBoundingBox.GetX(), boardBoundingBox.GetY(), boardBoundingBox.GetWidth(), boardBoundingBox.GetHeight() ); // Compute the PCB size in internal units userscale = m_PrintParams.m_PrintScale; if( m_PrintParams.m_PrintScale == 0 ) // fit in page option { if(boardBoundingBox.GetWidth() && boardBoundingBox.GetHeight()) { int margin = Millimeter2iu( 10.0 ); // add a margin around the drawings double scaleX = (double)(pageSizeIU.x - (2 * margin)) / boardBoundingBox.GetWidth(); double scaleY = (double)(pageSizeIU.y - (2 * margin)) / boardBoundingBox.GetHeight(); userscale = (scaleX < scaleY) ? scaleX : scaleY; } else userscale = 1.0; } wxSize scaledPageSize = pageSizeIU; drawRect.SetSize( scaledPageSize ); scaledPageSize.x = wxRound( scaledPageSize.x / userscale ); scaledPageSize.y = wxRound( scaledPageSize.y / userscale ); if( m_PrintParams.m_PageSetupData ) { wxLogTrace( tracePrinting, wxT( "Fit size to page margins: x=%d, y=%d" ), scaledPageSize.x, scaledPageSize.y ); // Always scale to the size of the paper. FitThisSizeToPageMargins( scaledPageSize, *m_PrintParams.m_PageSetupData ); } // Compute Accurate scale 1 if( m_PrintParams.m_PrintScale == 1.0 ) { // We want a 1:1 scale, regardless the page setup // like page size, margin ... MapScreenSizeToPaper(); // set best scale and offset (scale is not used) int w, h; GetPPIPrinter( &w, &h ); double accurate_Xscale = (double) w / (IU_PER_MILS*1000); double accurate_Yscale = (double) h / (IU_PER_MILS*1000); if( IsPreview() ) // Scale must take in account the DC size in Preview { // Get the size of the DC in pixels wxSize PlotAreaSize; dc->GetSize( &PlotAreaSize.x, &PlotAreaSize.y ); GetPageSizePixels( &w, &h ); accurate_Xscale *= (double)PlotAreaSize.x / w; accurate_Yscale *= (double)PlotAreaSize.y / h; } // Fine scale adjust accurate_Xscale *= m_PrintParams.m_XScaleAdjust; accurate_Yscale *= m_PrintParams.m_YScaleAdjust; // Set print scale for 1:1 exact scale dc->SetUserScale( accurate_Xscale, accurate_Yscale ); } // Get the final size of the DC in pixels wxSize PlotAreaSizeInPixels; dc->GetSize( &PlotAreaSizeInPixels.x, &PlotAreaSizeInPixels.y ); wxLogTrace( tracePrinting, wxT( "Plot area in pixels: x=%d, y=%d" ), PlotAreaSizeInPixels.x, PlotAreaSizeInPixels.y ); double scalex, scaley; dc->GetUserScale( &scalex, &scaley ); wxLogTrace( tracePrinting, wxT( "DC user scale: x=%g, y=%g" ), scalex, scaley ); wxSize PlotAreaSizeInUserUnits; PlotAreaSizeInUserUnits.x = KiROUND( PlotAreaSizeInPixels.x / scalex ); PlotAreaSizeInUserUnits.y = KiROUND( PlotAreaSizeInPixels.y / scaley ); wxLogTrace( tracePrinting, wxT( "Scaled plot area in user units: x=%d, y=%d" ), PlotAreaSizeInUserUnits.x, PlotAreaSizeInUserUnits.y ); // In module editor, the module is located at 0,0 but for printing // it is moved to pageSizeIU.x/2, pageSizeIU.y/2. // So the equivalent board must be moved to the center of the page: if( m_Parent->IsType( MODULE_EDITOR_FRAME_TYPE ) ) { boardBoundingBox.Move( wxPoint( pageSizeIU.x/2, pageSizeIU.y/2 ) ); } // In some cases the plot origin is the centre of the board outline rather than the center // of the selected paper size. if( m_PrintParams.CenterOnBoardOutline() ) { // Here we are only drawing the board and it's contents. drawRect = boardBoundingBox; offset.x += wxRound( (double) -scaledPageSize.x / 2.0 ); offset.y += wxRound( (double) -scaledPageSize.y / 2.0 ); wxPoint center = boardBoundingBox.Centre(); if( printMirror ) { // Calculate the mirrored center of the board. center.x = m_Parent->GetPageSizeIU().x - boardBoundingBox.Centre().x; } offset += center; } GRResetPenAndBrush( dc ); EDA_DRAW_PANEL* panel = m_Parent->GetCanvas(); EDA_RECT tmp = *panel->GetClipBox(); // Set clip box to the max size #define MAX_VALUE (INT_MAX/2) // MAX_VALUE is the max we can use in an integer // and that allows calculations without overflow panel->SetClipBox( EDA_RECT( wxPoint( 0, 0 ), wxSize( MAX_VALUE, MAX_VALUE ) ) ); screen->m_IsPrinting = true; EDA_COLOR_T bg_color = g_DrawBgColor; // Print frame reference, if reqquested, before if( m_PrintParams.m_Print_Black_and_White ) GRForceBlackPen( true ); if( m_PrintParams.PrintBorderAndTitleBlock() ) m_Parent->DrawWorkSheet( dc, screen, m_PrintParams.m_PenDefaultSize, IU_PER_MILS, titleblockFilename ); if( printMirror ) { // To plot mirror, we reverse the x axis, and modify the plot x origin dc->SetAxisOrientation( false, false); /* Plot offset x is moved by the x plot area size in order to have * the old draw area in the new draw area, because the draw origin has not moved * (this is the upper left corner) but the X axis is reversed, therefore the plotting area * is the x coordinate values from - PlotAreaSize.x to 0 */ int x_dc_offset = PlotAreaSizeInPixels.x; x_dc_offset = KiROUND( x_dc_offset * userscale ); dc->SetDeviceOrigin( x_dc_offset, 0 ); wxLogTrace( tracePrinting, wxT( "Device origin: x=%d, y=%d" ), x_dc_offset, 0 ); panel->SetClipBox( EDA_RECT( wxPoint( -MAX_VALUE/2, -MAX_VALUE/2 ), panel->GetClipBox()->GetSize() ) ); } // screen->m_DrawOrg = offset; dc->SetLogicalOrigin( offset.x, offset.y ); wxLogTrace( tracePrinting, wxT( "Logical origin: x=%d, y=%d" ), offset.x, offset.y ); #if defined(wxUSE_LOG_TRACE) && defined( DEBUG ) wxRect paperRect = GetPaperRectPixels(); wxLogTrace( tracePrinting, wxT( "Paper rectangle: left=%d, top=%d, " "right=%d, bottom=%d" ), paperRect.GetLeft(), paperRect.GetTop(), paperRect.GetRight(), paperRect.GetBottom() ); int devLeft = dc->LogicalToDeviceX( drawRect.GetX() ); int devTop = dc->LogicalToDeviceY( drawRect.GetY() ); int devRight = dc->LogicalToDeviceX( drawRect.GetRight() ); int devBottom = dc->LogicalToDeviceY( drawRect.GetBottom() ); wxLogTrace( tracePrinting, wxT( "Final device rectangle: left=%d, top=%d, " "right=%d, bottom=%d\n" ), devLeft, devTop, devRight, devBottom ); #endif g_DrawBgColor = WHITE; /* when printing in color mode, we use the graphic OR mode that gives the same look as * the screen but because the background is white when printing, we must use a trick: * In order to plot on a white background in OR mode we must: * 1 - Plot all items in black, this creates a local black background * 2 - Plot in OR mode on black "local" background */ if( !m_PrintParams.m_Print_Black_and_White ) { // Creates a "local" black background GRForceBlackPen( true ); m_Parent->PrintPage( dc, m_PrintParams.m_PrintMaskLayer, printMirror, &m_PrintParams ); GRForceBlackPen( false ); } else GRForceBlackPen( true ); #if defined (GERBVIEW) // In B&W mode, do not force black pen for Gerbview // because negative objects need a white pen, not a black pen // B&W mode is handled in print page GRForceBlackPen( false ); #endif m_Parent->PrintPage( dc, m_PrintParams.m_PrintMaskLayer, printMirror, &m_PrintParams ); g_DrawBgColor = bg_color; screen->m_IsPrinting = false; panel->SetClipBox( tmp ); GRForceBlackPen( false ); }
/** * 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 ); } }
const EDA_RECT DRAWSEGMENT::GetBoundingBox() const { EDA_RECT bbox; bbox.SetOrigin( m_Start ); switch( m_Shape ) { case S_SEGMENT: bbox.SetEnd( m_End ); break; case S_CIRCLE: bbox.Inflate( GetRadius() ); break; case S_ARC: { bbox.Merge( m_End ); wxPoint end = m_End; RotatePoint( &end, m_Start, -m_Angle ); bbox.Merge( end ); } break; case S_POLYGON: { wxPoint p_end; MODULE* module = GetParentModule(); for( unsigned ii = 0; ii < m_PolyPoints.size(); ii++ ) { wxPoint pt = m_PolyPoints[ii]; if( module ) // Transform, if we belong to a module { RotatePoint( &pt, module->GetOrientation() ); pt += module->GetPosition(); } if( ii == 0 ) p_end = pt; bbox.SetX( std::min( bbox.GetX(), pt.x ) ); bbox.SetY( std::min( bbox.GetY(), pt.y ) ); p_end.x = std::max( p_end.x, pt.x ); p_end.y = std::max( p_end.y, pt.y ); } bbox.SetEnd( p_end ); } break; default: ; } bbox.Inflate( ((m_Width+1) / 2) + 1 ); bbox.Normalize(); return bbox; }
const EDA_RECT DRAWSEGMENT::GetBoundingBox() const { EDA_RECT bbox; bbox.SetOrigin( m_Start ); switch( m_Shape ) { case S_SEGMENT: bbox.SetEnd( m_End ); break; case S_CIRCLE: bbox.Inflate( GetRadius() ); break; case S_ARC: { bbox.Merge( m_End ); wxPoint end = m_End; RotatePoint( &end, m_Start, -m_Angle ); bbox.Merge( end ); // Determine the starting quarter // 0 right-bottom // 1 left-bottom // 2 left-top // 3 right-top unsigned int quarter = 0; // assume right-bottom if( m_End.y < m_Start.y ) // change to left-top quarter |= 3; if( m_End.x < m_Start.x ) // for left side, the LSB is 2nd bit negated quarter ^= 1; int radius = GetRadius(); int angle = (int) GetArcAngleStart() % 900 + m_Angle; bool directionCW = ( m_Angle > 0 ); // Is the direction of arc clockwise? if( !directionCW ) { angle = 900 - angle; quarter = ( quarter + 3 ) % 4; // -1 modulo arithmetic } while( angle > 900 ) { switch( quarter ) { case 0: bbox.Merge( wxPoint( m_Start.x, m_Start.y + radius ) ); // down break; case 1: bbox.Merge( wxPoint( m_Start.x - radius, m_Start.y ) ); // left break; case 2: bbox.Merge( wxPoint( m_Start.x, m_Start.y - radius ) ); // up break; case 3: bbox.Merge( wxPoint( m_Start.x + radius, m_Start.y ) ); // right break; } if( directionCW ) ++quarter; else quarter += 3; // -1 modulo arithmetic quarter %= 4; angle -= 900; } } break; case S_POLYGON: { wxPoint p_end; MODULE* module = GetParentModule(); for( unsigned ii = 0; ii < m_PolyPoints.size(); ii++ ) { wxPoint pt = m_PolyPoints[ii]; if( module ) // Transform, if we belong to a module { RotatePoint( &pt, module->GetOrientation() ); pt += module->GetPosition(); } if( ii == 0 ) p_end = pt; bbox.SetX( std::min( bbox.GetX(), pt.x ) ); bbox.SetY( std::min( bbox.GetY(), pt.y ) ); p_end.x = std::max( p_end.x, pt.x ); p_end.y = std::max( p_end.y, pt.y ); } bbox.SetEnd( p_end ); } break; default: ; } bbox.Inflate( ((m_Width+1) / 2) + 1 ); bbox.Normalize(); return bbox; }
int ZONE_CONTAINER::FillZoneAreasWithSegments() { int ics, ice; int count = 0; std::vector <int> x_coordinates; bool error = false; int istart, iend; // index of the starting and the endif corner of one filled area in m_FilledPolysList int margin = m_ZoneMinThickness * 2 / 10; int minwidth = Mils2iu( 2 ); margin = std::max ( minwidth, margin ); int step = m_ZoneMinThickness - margin; step = std::max( step, minwidth ); // Read all filled areas in m_FilledPolysList m_FillSegmList.clear(); istart = 0; int end_list = m_FilledPolysList.GetCornersCount()-1; for( int ic = 0; ic <= end_list; ic++ ) { CPolyPt* corner = &m_FilledPolysList[ic]; if ( corner->end_contour || (ic == end_list) ) { iend = ic; EDA_RECT rect = CalculateSubAreaBoundaryBox( istart, iend ); // Calculate the y limits of the zone int refy = rect.GetY(); int endy = rect.GetBottom(); for( ; refy < endy; refy += step ) { // find all intersection points of an infinite line with polyline sides x_coordinates.clear(); for( ics = istart, ice = iend; ics <= iend; ice = ics, ics++ ) { if ( m_FilledPolysList[ice].m_utility ) continue; int seg_startX = m_FilledPolysList[ics].x; int seg_startY = m_FilledPolysList[ics].y; int seg_endX = m_FilledPolysList[ice].x; int seg_endY = m_FilledPolysList[ice].y; /* Trivial cases: skip if ref above or below the segment to test */ if( ( seg_startY > refy ) && (seg_endY > refy ) ) continue; // segment below ref point, or its Y end pos on Y coordinate ref point: skip if( ( seg_startY <= refy ) && (seg_endY <= refy ) ) continue; /* at this point refy is between seg_startY and seg_endY * see if an horizontal line at Y = refy is intersecting this segment */ // calculate the x position of the intersection of this segment and the // infinite line this is more easier if we move the X,Y axis origin to // the segment start point: seg_endX -= seg_startX; seg_endY -= seg_startY; double newrefy = (double) (refy - seg_startY); double intersec_x; if ( seg_endY == 0 ) // horizontal segment on the same line: skip continue; // Now calculate the x intersection coordinate of the horizontal line at // y = newrefy and the segment from (0,0) to (seg_endX,seg_endY) with the // horizontal line at the new refy position the line slope is: // slope = seg_endY/seg_endX; and inv_slope = seg_endX/seg_endY // and the x pos relative to the new origin is: // intersec_x = refy/slope = refy * inv_slope // Note: because horizontal segments are already tested and skipped, slope // exists (seg_end_y not O) double inv_slope = (double)seg_endX / seg_endY; intersec_x = newrefy * inv_slope; x_coordinates.push_back((int) intersec_x + seg_startX); } // A line scan is finished: build list of segments // Sort intersection points by increasing x value: // So 2 consecutive points are the ends of a segment sort( x_coordinates.begin(), x_coordinates.end(), SortByXValues ); // Create segments if ( !error && ( x_coordinates.size() & 1 ) != 0 ) { // An even number of coordinates is expected, because a segment has 2 ends. // An if this algorithm always works, it must always find an even count. wxString msg = wxT("Fill Zone: odd number of points at y = "); msg << refy; wxMessageBox(msg ); error = true; } if ( error ) break; int iimax = x_coordinates.size()-1; for (int ii = 0; ii < iimax; ii +=2 ) { wxPoint seg_start, seg_end; count++; seg_start.x = x_coordinates[ii]; seg_start.y = refy; seg_end.x = x_coordinates[ii+1]; seg_end.y = refy; SEGMENT segment( seg_start, seg_end ); m_FillSegmList.push_back( segment ); } } //End examine segments in one area if ( error ) break; istart = iend + 1; // istart points the first corner of the next area } // End find one end of outline if ( error ) break; } // End examine all areas return count; }