Loading pcbnew/board_items_to_polygon_shape_transform.cpp +136 −70 Original line number Diff line number Diff line Loading @@ -27,8 +27,8 @@ * @brief function to convert shapes of items ( pads, tracks... ) to polygons */ /* Function to convert pads and tranck shapes to polygons * Used to fill zones areas /* Function to convert pad and track shapes to polygons * Used to fill zones areas and in 3D viewer */ #include <vector> Loading Loading @@ -520,22 +520,19 @@ void TRACK:: TransformShapeWithClearanceToPolygon( CPOLYGONS_LIST& aCornerBuffer * clearance when the circle is approximated by segment bigger or equal * to the real clearance value (usually near from 1.0) */ #include <clipper.hpp> void D_PAD:: TransformShapeWithClearanceToPolygon( CPOLYGONS_LIST& aCornerBuffer, int aClearanceValue, int aCircleToSegmentsCount, double aCorrectionFactor ) const { wxPoint corner_position; double angle; double angle = m_Orient; int dx = (m_Size.x / 2) + aClearanceValue; int dy = (m_Size.y / 2) + aClearanceValue; double delta = 3600.0 / aCircleToSegmentsCount; // rot angle in 0.1 degree wxPoint PadShapePos = ShapePos(); /* Note: for pad having a shape offset, * the pad position is NOT the shape position */ wxSize psize = m_Size; /* pad size unsed in RECT and TRAPEZOIDAL pads * trapezoidal pads are considered as rect * pad shape having they boudary box size */ switch( GetShape() ) { Loading @@ -547,7 +544,6 @@ void D_PAD:: TransformShapeWithClearanceToPolygon( CPOLYGONS_LIST& aCornerBuffer case PAD_OVAL: // An oval pad has the same shape as a segment with rounded ends angle = m_Orient; { int width; wxPoint shape_offset; Loading @@ -573,77 +569,51 @@ void D_PAD:: TransformShapeWithClearanceToPolygon( CPOLYGONS_LIST& aCornerBuffer break; case PAD_TRAPEZOID: psize.x += std::abs( m_DeltaSize.y ); psize.y += std::abs( m_DeltaSize.x ); // fall through case PAD_RECT: // Easy implementation for rectangular cutouts with rounded corners angle = m_Orient; // Corner rounding radius int rounding_radius = KiROUND( aClearanceValue * aCorrectionFactor ); double angle_pg; // Polygon increment angle for( int i = 0; i < aCircleToSegmentsCount / 4 + 1; i++ ) { corner_position = wxPoint( 0, -rounding_radius ); RotatePoint( &corner_position, (1800.0 / aCircleToSegmentsCount) ); wxPoint corners[4]; BuildPadPolygon( corners, wxSize( 0, 0 ), angle ); // Start at half increment offset angle_pg = i * delta; RotatePoint( &corner_position, angle_pg ); // We are using ClipperLib to inflate the polygon shape, using // arcs to connect moved segments. ClipperLib::Path outline; ClipperLib::Paths shapeWithClearance; // Rounding vector rotation corner_position -= psize / 2; // Rounding vector + Pad corner offset RotatePoint( &corner_position, angle ); for( int ii = 0; ii < 4; ii++ ) outline << ClipperLib::IntPoint( corners[ii].x, corners[ii].y ); // Rotate according to module orientation corner_position += PadShapePos; // Shift origin to position CPolyPt polypoint( corner_position.x, corner_position.y ); aCornerBuffer.Append( polypoint ); } ClipperLib::ClipperOffset offset_engine; // Prepare an offset (inflate) transform, with edges connected by arcs offset_engine.AddPath( outline, ClipperLib::jtRound, ClipperLib::etClosedPolygon ); for( int i = 0; i < aCircleToSegmentsCount / 4 + 1; i++ ) { corner_position = wxPoint( -rounding_radius, 0 ); RotatePoint( &corner_position, (1800.0 / aCircleToSegmentsCount) ); angle_pg = i * delta; RotatePoint( &corner_position, angle_pg ); corner_position -= wxPoint( psize.x / 2, -psize.y / 2 ); RotatePoint( &corner_position, angle ); corner_position += PadShapePos; CPolyPt polypoint( corner_position.x, corner_position.y ); aCornerBuffer.Append( polypoint ); } // Clipper approximates arcs by segments // It uses a value called ArcTolerance which is the max error between the arc // and segments created to approximate this arc // the number of segm per circle is: // n = PI / acos(1 - arc_tolerance / (arc radius)) // the arc radius is aClearanceValue // because arc_tolerance is << aClearanceValue and aClearanceValue >= 0 // n = PI / (arc_tolerance / aClearanceValue ) offset_engine.ArcTolerance = (double)aClearanceValue / 3.14 / aCircleToSegmentsCount; for( int i = 0; i < aCircleToSegmentsCount / 4 + 1; i++ ) { corner_position = wxPoint( 0, rounding_radius ); RotatePoint( &corner_position, (1800.0 / aCircleToSegmentsCount) ); angle_pg = i * delta; RotatePoint( &corner_position, angle_pg ); corner_position += psize / 2; RotatePoint( &corner_position, angle ); corner_position += PadShapePos; CPolyPt polypoint( corner_position.x, corner_position.y ); aCornerBuffer.Append( polypoint ); } double rounding_radius = aClearanceValue * aCorrectionFactor; offset_engine.Execute( shapeWithClearance, rounding_radius ); for( int i = 0; i < aCircleToSegmentsCount / 4 + 1; i++ ) // get new outline (only one polygon is expected) // For info, ClipperLib uses long long to handle integer coordinates ClipperLib::Path& polygon = shapeWithClearance[0]; for( unsigned jj = 0; jj < polygon.size(); jj++ ) { corner_position = wxPoint( rounding_radius, 0 ); RotatePoint( &corner_position, (1800.0 / aCircleToSegmentsCount) ); angle_pg = i * delta; RotatePoint( &corner_position, angle_pg ); corner_position -= wxPoint( -psize.x / 2, psize.y / 2 ); RotatePoint( &corner_position, angle ); corner_position.x = int( polygon[jj].X ); corner_position.y = int( polygon[jj].Y ); corner_position += PadShapePos; CPolyPt polypoint( corner_position.x, corner_position.y ); aCornerBuffer.Append( polypoint ); } aCornerBuffer.CloseLastContour(); } break; } } Loading Loading @@ -1090,9 +1060,105 @@ void CreateThermalReliefPadPolygon( CPOLYGONS_LIST& aCornerBuffer, aCornerBuffer.CloseLastContour(); angle = AddAngles( angle, 1800 ); } } break; case PAD_TRAPEZOID: { CPOLYGONS_LIST cbuffer; // We need a length to build the stubs of the thermal reliefs // the value is not very important. The pad bounding box gives a reasonable value EDA_RECT bbox = aPad.GetBoundingBox(); int stub_len = std::max( bbox.GetWidth(), bbox.GetHeight() ); aPad.TransformShapeWithClearanceToPolygon( cbuffer, aThermalGap, aCircleToSegmentsCount, aCorrectionFactor ); // We are using ClipperLib to substract stubs to clearance area (antipad area). ClipperLib::Path antipad; // The full antipad area ClipperLib::Path stub; // A basic stub ( a rectangle) ClipperLib::Paths stubs; // the full stubs shape ClipperLib::Paths thermalShape; // the holes in copper zone // cbuffer is expected to contain only one polygon, which is // area of the pad + the thermal gap (the antipad) for( unsigned ii = 0; ii < cbuffer.GetCornersCount(); ii++ ) antipad << ClipperLib::IntPoint( cbuffer.GetPos(ii).x, cbuffer.GetPos(ii).y ); // We now substract the stubs (connections to the copper zone) ClipperLib::Clipper clip_engine; // Prepare a clipping transform clip_engine.AddPath( antipad, ClipperLib::ptSubject, true ); // Create stubs and add them to clipper engine wxPoint stubBuffer[4]; stubBuffer[0].x = stub_len; stubBuffer[0].y = copper_thickness.y/2; stubBuffer[1] = stubBuffer[0]; stubBuffer[1].y = -copper_thickness.y/2; stubBuffer[2] = stubBuffer[1]; stubBuffer[2].x = -stub_len; stubBuffer[3] = stubBuffer[2]; stubBuffer[3].y = copper_thickness.y/2; for( unsigned ii = 0; ii < DIM( stubBuffer ); ii++ ) { wxPoint cpos = stubBuffer[ii]; RotatePoint( &cpos, aPad.GetOrientation() ); cpos += PadShapePos; stub << ClipperLib::IntPoint( cpos.x, cpos.y ); } ClipperLib::Clipper stubs_engine; stubs_engine.AddPath( stub, ClipperLib::ptSubject, true ); stubBuffer[0].y = stub_len; stubBuffer[0].x = copper_thickness.x/2; stubBuffer[1] = stubBuffer[0]; stubBuffer[1].x = -copper_thickness.x/2; stubBuffer[2] = stubBuffer[1]; stubBuffer[2].y = -stub_len; stubBuffer[3] = stubBuffer[2]; stubBuffer[3].x = copper_thickness.x/2; stub.clear(); for( unsigned ii = 0; ii < DIM( stubBuffer ); ii++ ) { wxPoint cpos = stubBuffer[ii]; RotatePoint( &cpos, aPad.GetOrientation() ); cpos += PadShapePos; stub << ClipperLib::IntPoint( cpos.x, cpos.y ); } stubs_engine.AddPath( stub, ClipperLib::ptClip, true ); // Build the full stubs shape: stubs_engine.Execute( ClipperLib::ctUnion, stubs ); // remove stubs to antipad area (i.e. add copper stubs) clip_engine.AddPath( stubs[0], ClipperLib::ptClip, true ); clip_engine.Execute( ClipperLib::ctDifference, thermalShape ); // put thermal shapes (holes) to list: wxPoint corner_position; for( unsigned ii = 0; ii < thermalShape.size(); ii++ ) { ClipperLib::Path& polygon = thermalShape[ii]; for( unsigned jj = 0; jj < polygon.size(); jj++ ) { corner_position.x = int( polygon[jj].X ); corner_position.y = int( polygon[jj].Y ); CPolyPt polypoint( corner_position.x, corner_position.y ); aCornerBuffer.Append( polypoint ); } aCornerBuffer.CloseLastContour(); } break; } default: ; Loading pcbnew/zones_convert_brd_items_to_polygons_with_Boost.cpp +1 −5 Original line number Diff line number Diff line Loading @@ -249,11 +249,7 @@ void ZONE_CONTAINER::AddClearanceAreasPolygonsToPolysList( BOARD* aPcb ) continue; } if( ( GetPadConnection( pad ) == PAD_NOT_IN_ZONE ) || ( pad->GetShape() == PAD_TRAPEZOID ) ) // PAD_TRAPEZOID shapes are not in zones because they are used in microwave apps // and i think it is good that shapes are not changed by thermal pads or others if( GetPadConnection( pad ) == PAD_NOT_IN_ZONE ) { int gap = zone_clearance; int thermalGap = GetThermalReliefGap( pad ); Loading Loading
pcbnew/board_items_to_polygon_shape_transform.cpp +136 −70 Original line number Diff line number Diff line Loading @@ -27,8 +27,8 @@ * @brief function to convert shapes of items ( pads, tracks... ) to polygons */ /* Function to convert pads and tranck shapes to polygons * Used to fill zones areas /* Function to convert pad and track shapes to polygons * Used to fill zones areas and in 3D viewer */ #include <vector> Loading Loading @@ -520,22 +520,19 @@ void TRACK:: TransformShapeWithClearanceToPolygon( CPOLYGONS_LIST& aCornerBuffer * clearance when the circle is approximated by segment bigger or equal * to the real clearance value (usually near from 1.0) */ #include <clipper.hpp> void D_PAD:: TransformShapeWithClearanceToPolygon( CPOLYGONS_LIST& aCornerBuffer, int aClearanceValue, int aCircleToSegmentsCount, double aCorrectionFactor ) const { wxPoint corner_position; double angle; double angle = m_Orient; int dx = (m_Size.x / 2) + aClearanceValue; int dy = (m_Size.y / 2) + aClearanceValue; double delta = 3600.0 / aCircleToSegmentsCount; // rot angle in 0.1 degree wxPoint PadShapePos = ShapePos(); /* Note: for pad having a shape offset, * the pad position is NOT the shape position */ wxSize psize = m_Size; /* pad size unsed in RECT and TRAPEZOIDAL pads * trapezoidal pads are considered as rect * pad shape having they boudary box size */ switch( GetShape() ) { Loading @@ -547,7 +544,6 @@ void D_PAD:: TransformShapeWithClearanceToPolygon( CPOLYGONS_LIST& aCornerBuffer case PAD_OVAL: // An oval pad has the same shape as a segment with rounded ends angle = m_Orient; { int width; wxPoint shape_offset; Loading @@ -573,77 +569,51 @@ void D_PAD:: TransformShapeWithClearanceToPolygon( CPOLYGONS_LIST& aCornerBuffer break; case PAD_TRAPEZOID: psize.x += std::abs( m_DeltaSize.y ); psize.y += std::abs( m_DeltaSize.x ); // fall through case PAD_RECT: // Easy implementation for rectangular cutouts with rounded corners angle = m_Orient; // Corner rounding radius int rounding_radius = KiROUND( aClearanceValue * aCorrectionFactor ); double angle_pg; // Polygon increment angle for( int i = 0; i < aCircleToSegmentsCount / 4 + 1; i++ ) { corner_position = wxPoint( 0, -rounding_radius ); RotatePoint( &corner_position, (1800.0 / aCircleToSegmentsCount) ); wxPoint corners[4]; BuildPadPolygon( corners, wxSize( 0, 0 ), angle ); // Start at half increment offset angle_pg = i * delta; RotatePoint( &corner_position, angle_pg ); // We are using ClipperLib to inflate the polygon shape, using // arcs to connect moved segments. ClipperLib::Path outline; ClipperLib::Paths shapeWithClearance; // Rounding vector rotation corner_position -= psize / 2; // Rounding vector + Pad corner offset RotatePoint( &corner_position, angle ); for( int ii = 0; ii < 4; ii++ ) outline << ClipperLib::IntPoint( corners[ii].x, corners[ii].y ); // Rotate according to module orientation corner_position += PadShapePos; // Shift origin to position CPolyPt polypoint( corner_position.x, corner_position.y ); aCornerBuffer.Append( polypoint ); } ClipperLib::ClipperOffset offset_engine; // Prepare an offset (inflate) transform, with edges connected by arcs offset_engine.AddPath( outline, ClipperLib::jtRound, ClipperLib::etClosedPolygon ); for( int i = 0; i < aCircleToSegmentsCount / 4 + 1; i++ ) { corner_position = wxPoint( -rounding_radius, 0 ); RotatePoint( &corner_position, (1800.0 / aCircleToSegmentsCount) ); angle_pg = i * delta; RotatePoint( &corner_position, angle_pg ); corner_position -= wxPoint( psize.x / 2, -psize.y / 2 ); RotatePoint( &corner_position, angle ); corner_position += PadShapePos; CPolyPt polypoint( corner_position.x, corner_position.y ); aCornerBuffer.Append( polypoint ); } // Clipper approximates arcs by segments // It uses a value called ArcTolerance which is the max error between the arc // and segments created to approximate this arc // the number of segm per circle is: // n = PI / acos(1 - arc_tolerance / (arc radius)) // the arc radius is aClearanceValue // because arc_tolerance is << aClearanceValue and aClearanceValue >= 0 // n = PI / (arc_tolerance / aClearanceValue ) offset_engine.ArcTolerance = (double)aClearanceValue / 3.14 / aCircleToSegmentsCount; for( int i = 0; i < aCircleToSegmentsCount / 4 + 1; i++ ) { corner_position = wxPoint( 0, rounding_radius ); RotatePoint( &corner_position, (1800.0 / aCircleToSegmentsCount) ); angle_pg = i * delta; RotatePoint( &corner_position, angle_pg ); corner_position += psize / 2; RotatePoint( &corner_position, angle ); corner_position += PadShapePos; CPolyPt polypoint( corner_position.x, corner_position.y ); aCornerBuffer.Append( polypoint ); } double rounding_radius = aClearanceValue * aCorrectionFactor; offset_engine.Execute( shapeWithClearance, rounding_radius ); for( int i = 0; i < aCircleToSegmentsCount / 4 + 1; i++ ) // get new outline (only one polygon is expected) // For info, ClipperLib uses long long to handle integer coordinates ClipperLib::Path& polygon = shapeWithClearance[0]; for( unsigned jj = 0; jj < polygon.size(); jj++ ) { corner_position = wxPoint( rounding_radius, 0 ); RotatePoint( &corner_position, (1800.0 / aCircleToSegmentsCount) ); angle_pg = i * delta; RotatePoint( &corner_position, angle_pg ); corner_position -= wxPoint( -psize.x / 2, psize.y / 2 ); RotatePoint( &corner_position, angle ); corner_position.x = int( polygon[jj].X ); corner_position.y = int( polygon[jj].Y ); corner_position += PadShapePos; CPolyPt polypoint( corner_position.x, corner_position.y ); aCornerBuffer.Append( polypoint ); } aCornerBuffer.CloseLastContour(); } break; } } Loading Loading @@ -1090,9 +1060,105 @@ void CreateThermalReliefPadPolygon( CPOLYGONS_LIST& aCornerBuffer, aCornerBuffer.CloseLastContour(); angle = AddAngles( angle, 1800 ); } } break; case PAD_TRAPEZOID: { CPOLYGONS_LIST cbuffer; // We need a length to build the stubs of the thermal reliefs // the value is not very important. The pad bounding box gives a reasonable value EDA_RECT bbox = aPad.GetBoundingBox(); int stub_len = std::max( bbox.GetWidth(), bbox.GetHeight() ); aPad.TransformShapeWithClearanceToPolygon( cbuffer, aThermalGap, aCircleToSegmentsCount, aCorrectionFactor ); // We are using ClipperLib to substract stubs to clearance area (antipad area). ClipperLib::Path antipad; // The full antipad area ClipperLib::Path stub; // A basic stub ( a rectangle) ClipperLib::Paths stubs; // the full stubs shape ClipperLib::Paths thermalShape; // the holes in copper zone // cbuffer is expected to contain only one polygon, which is // area of the pad + the thermal gap (the antipad) for( unsigned ii = 0; ii < cbuffer.GetCornersCount(); ii++ ) antipad << ClipperLib::IntPoint( cbuffer.GetPos(ii).x, cbuffer.GetPos(ii).y ); // We now substract the stubs (connections to the copper zone) ClipperLib::Clipper clip_engine; // Prepare a clipping transform clip_engine.AddPath( antipad, ClipperLib::ptSubject, true ); // Create stubs and add them to clipper engine wxPoint stubBuffer[4]; stubBuffer[0].x = stub_len; stubBuffer[0].y = copper_thickness.y/2; stubBuffer[1] = stubBuffer[0]; stubBuffer[1].y = -copper_thickness.y/2; stubBuffer[2] = stubBuffer[1]; stubBuffer[2].x = -stub_len; stubBuffer[3] = stubBuffer[2]; stubBuffer[3].y = copper_thickness.y/2; for( unsigned ii = 0; ii < DIM( stubBuffer ); ii++ ) { wxPoint cpos = stubBuffer[ii]; RotatePoint( &cpos, aPad.GetOrientation() ); cpos += PadShapePos; stub << ClipperLib::IntPoint( cpos.x, cpos.y ); } ClipperLib::Clipper stubs_engine; stubs_engine.AddPath( stub, ClipperLib::ptSubject, true ); stubBuffer[0].y = stub_len; stubBuffer[0].x = copper_thickness.x/2; stubBuffer[1] = stubBuffer[0]; stubBuffer[1].x = -copper_thickness.x/2; stubBuffer[2] = stubBuffer[1]; stubBuffer[2].y = -stub_len; stubBuffer[3] = stubBuffer[2]; stubBuffer[3].x = copper_thickness.x/2; stub.clear(); for( unsigned ii = 0; ii < DIM( stubBuffer ); ii++ ) { wxPoint cpos = stubBuffer[ii]; RotatePoint( &cpos, aPad.GetOrientation() ); cpos += PadShapePos; stub << ClipperLib::IntPoint( cpos.x, cpos.y ); } stubs_engine.AddPath( stub, ClipperLib::ptClip, true ); // Build the full stubs shape: stubs_engine.Execute( ClipperLib::ctUnion, stubs ); // remove stubs to antipad area (i.e. add copper stubs) clip_engine.AddPath( stubs[0], ClipperLib::ptClip, true ); clip_engine.Execute( ClipperLib::ctDifference, thermalShape ); // put thermal shapes (holes) to list: wxPoint corner_position; for( unsigned ii = 0; ii < thermalShape.size(); ii++ ) { ClipperLib::Path& polygon = thermalShape[ii]; for( unsigned jj = 0; jj < polygon.size(); jj++ ) { corner_position.x = int( polygon[jj].X ); corner_position.y = int( polygon[jj].Y ); CPolyPt polypoint( corner_position.x, corner_position.y ); aCornerBuffer.Append( polypoint ); } aCornerBuffer.CloseLastContour(); } break; } default: ; Loading
pcbnew/zones_convert_brd_items_to_polygons_with_Boost.cpp +1 −5 Original line number Diff line number Diff line Loading @@ -249,11 +249,7 @@ void ZONE_CONTAINER::AddClearanceAreasPolygonsToPolysList( BOARD* aPcb ) continue; } if( ( GetPadConnection( pad ) == PAD_NOT_IN_ZONE ) || ( pad->GetShape() == PAD_TRAPEZOID ) ) // PAD_TRAPEZOID shapes are not in zones because they are used in microwave apps // and i think it is good that shapes are not changed by thermal pads or others if( GetPadConnection( pad ) == PAD_NOT_IN_ZONE ) { int gap = zone_clearance; int thermalGap = GetThermalReliefGap( pad ); Loading