diff --git a/pcbnew/CMakeLists.txt b/pcbnew/CMakeLists.txt index 06e914d67f..1fdbad0231 100644 --- a/pcbnew/CMakeLists.txt +++ b/pcbnew/CMakeLists.txt @@ -262,6 +262,7 @@ set( PCBNEW_CLASS_SRCS array_pad_name_provider.cpp build_BOM_from_board.cpp cleanup_item.cpp + convert_drawsegment_list_to_polygon.cpp cross-probing.cpp edit.cpp edit_track_width.cpp diff --git a/pcbnew/class_drawsegment.cpp b/pcbnew/class_drawsegment.cpp index 6f651064a9..95c438daeb 100644 --- a/pcbnew/class_drawsegment.cpp +++ b/pcbnew/class_drawsegment.cpp @@ -187,9 +187,10 @@ void DRAWSEGMENT::Rotate( const wxPoint& aRotCentre, double aAngle ) case S_ARC: case S_SEGMENT: case S_CIRCLE: - // these can all be done by just rotating the start and end points - RotatePoint( &m_Start, aRotCentre, aAngle); - RotatePoint( &m_End, aRotCentre, aAngle); + // these can all be done by just rotating the constituent points + RotatePoint( &m_Start, aRotCentre, aAngle ); + RotatePoint( &m_End, aRotCentre, aAngle ); + RotatePoint( &m_ThirdPoint, aRotCentre, aAngle ); break; case S_RECT: diff --git a/pcbnew/class_drawsegment.h b/pcbnew/class_drawsegment.h index 621b438401..29547baa86 100644 --- a/pcbnew/class_drawsegment.h +++ b/pcbnew/class_drawsegment.h @@ -109,7 +109,7 @@ public: * sets the angle for arcs, and normalizes it within the range 0 - 360 degrees. * @param aAngle is tenths of degrees, but will soon be degrees. */ - void SetAngle( double aAngle ); // encapsulates the transition to degrees + virtual void SetAngle( double aAngle ); // encapsulates the transition to degrees double GetAngle() const { return m_Angle; } void SetType( int aType ) { m_Type = aType; } @@ -200,14 +200,18 @@ public: * to initialize one point of the cicumference */ void SetArcStart( const wxPoint& aArcStartPoint ) - { m_End = aArcStartPoint; } + { + m_End = aArcStartPoint; + } /** - * Initialize the start arc point. can be used for circles + * Initialize the end arc point. can be used for circles * to initialize one point of the cicumference */ void SetArcEnd( const wxPoint& aArcEndPoint ) - { m_ThirdPoint = aArcEndPoint; } + { + m_ThirdPoint = aArcEndPoint; + } /** For arcs and circles: */ diff --git a/pcbnew/class_edge_mod.cpp b/pcbnew/class_edge_mod.cpp index d20be5f84f..85fd30687d 100644 --- a/pcbnew/class_edge_mod.cpp +++ b/pcbnew/class_edge_mod.cpp @@ -58,6 +58,7 @@ void EDGE_MODULE::SetLocalCoord() { m_Start0 = m_Start; m_End0 = m_End; + m_ThirdPoint0 = m_ThirdPoint; m_Bezier0_C1 = m_BezierC1; m_Bezier0_C2 = m_BezierC2; return; @@ -65,11 +66,13 @@ void EDGE_MODULE::SetLocalCoord() m_Start0 = m_Start - module->GetPosition(); m_End0 = m_End - module->GetPosition(); + m_ThirdPoint0 = m_ThirdPoint - module->GetPosition(); m_Bezier0_C1 = m_BezierC1 - module->GetPosition(); m_Bezier0_C2 = m_BezierC2 - module->GetPosition(); double angle = module->GetOrientation(); RotatePoint( &m_Start0.x, &m_Start0.y, -angle ); RotatePoint( &m_End0.x, &m_End0.y, -angle ); + RotatePoint( &m_ThirdPoint0.x, &m_ThirdPoint0.y, -angle ); RotatePoint( &m_Bezier0_C1.x, &m_Bezier0_C1.y, -angle ); RotatePoint( &m_Bezier0_C2.x, &m_Bezier0_C2.y, -angle ); } @@ -79,20 +82,23 @@ void EDGE_MODULE::SetDrawCoord() { MODULE* module = (MODULE*) m_Parent; - m_Start = m_Start0; - m_End = m_End0; - m_BezierC1 = m_Bezier0_C1; - m_BezierC2 = m_Bezier0_C2; + m_Start = m_Start0; + m_End = m_End0; + m_ThirdPoint = m_ThirdPoint0; + m_BezierC1 = m_Bezier0_C1; + m_BezierC2 = m_Bezier0_C2; if( module ) { RotatePoint( &m_Start.x, &m_Start.y, module->GetOrientation() ); RotatePoint( &m_End.x, &m_End.y, module->GetOrientation() ); + RotatePoint( &m_ThirdPoint.x, &m_ThirdPoint.y, module->GetOrientation() ); RotatePoint( &m_BezierC1.x, &m_BezierC1.y, module->GetOrientation() ); RotatePoint( &m_BezierC2.x, &m_BezierC2.y, module->GetOrientation() ); - m_Start += module->GetPosition(); - m_End += module->GetPosition(); + m_Start += module->GetPosition(); + m_End += module->GetPosition(); + m_ThirdPoint += module->GetPosition(); m_BezierC1 += module->GetPosition(); m_BezierC2 += module->GetPosition(); } @@ -144,6 +150,17 @@ EDA_ITEM* EDGE_MODULE::Clone() const } +void EDGE_MODULE::SetAngle( double aAngle ) +{ + // Mark as depreciated. + // m_Angle does not define the arc anymore + // m_Angle must be >= -360 and <= +360 degrees + m_Angle = NormalizeAngle360Max( aAngle ); + m_ThirdPoint0 = m_End0; + RotatePoint( &m_ThirdPoint0, m_Start0, -m_Angle ); +} + + void EDGE_MODULE::Flip( const wxPoint& aCentre, bool aFlipLeftRight ) { wxPoint pt( 0, 0 ); @@ -166,10 +183,12 @@ void EDGE_MODULE::Flip( const wxPoint& aCentre, bool aFlipLeftRight ) { MIRROR( m_Start.x, aCentre.x ); MIRROR( m_End.x, aCentre.x ); + MIRROR( m_ThirdPoint.y, aCentre.x ); MIRROR( m_BezierC1.x, aCentre.x ); MIRROR( m_BezierC2.x, aCentre.x ); MIRROR( m_Start0.x, pt.x ); MIRROR( m_End0.x, pt.x ); + MIRROR( m_ThirdPoint0.x, pt.x ); MIRROR( m_Bezier0_C1.x, pt.x ); MIRROR( m_Bezier0_C2.x, pt.x ); } @@ -177,10 +196,12 @@ void EDGE_MODULE::Flip( const wxPoint& aCentre, bool aFlipLeftRight ) { MIRROR( m_Start.y, aCentre.y ); MIRROR( m_End.y, aCentre.y ); + MIRROR( m_ThirdPoint.y, aCentre.y ); MIRROR( m_BezierC1.y, aCentre.y ); MIRROR( m_BezierC2.y, aCentre.y ); MIRROR( m_Start0.y, pt.y ); MIRROR( m_End0.y, pt.y ); + MIRROR( m_ThirdPoint0.y, pt.y ); MIRROR( m_Bezier0_C1.y, pt.y ); MIRROR( m_Bezier0_C2.y, pt.y ); } @@ -270,10 +291,11 @@ void EDGE_MODULE::Move( const wxPoint& aMoveVector ) { // Move an edge of the footprint. // This is a footprint shape modification. - m_Start0 += aMoveVector; - m_End0 += aMoveVector; - m_Bezier0_C1 += aMoveVector; - m_Bezier0_C2 += aMoveVector; + m_Start0 += aMoveVector; + m_End0 += aMoveVector; + m_ThirdPoint0 += aMoveVector; + m_Bezier0_C1 += aMoveVector; + m_Bezier0_C2 += aMoveVector; switch( GetShape() ) { diff --git a/pcbnew/class_edge_mod.h b/pcbnew/class_edge_mod.h index 5484e6f109..141c0a65cf 100644 --- a/pcbnew/class_edge_mod.h +++ b/pcbnew/class_edge_mod.h @@ -72,6 +72,8 @@ public: return false; } + void SetAngle( double aAngle ) override; + /** * Move an edge of the footprint. * This is a footprint shape modification. @@ -111,6 +113,9 @@ public: void SetEnd0( const wxPoint& aPoint ) { m_End0 = aPoint; } const wxPoint& GetEnd0() const { return m_End0; } + void SetThirdPoint0( const wxPoint& aPoint ){ m_ThirdPoint0 = aPoint; } + const wxPoint& GetThirdPoint0() const { return m_ThirdPoint0; } + void SetBezier0_C1( const wxPoint& aPoint ) { m_Bezier0_C1 = aPoint; } const wxPoint& GetBezier0_C1() const { return m_Bezier0_C1; } @@ -151,6 +156,7 @@ public: wxPoint m_Start0; ///< Start point or center, relative to module origin, orient 0. wxPoint m_End0; ///< End point, relative to module origin, orient 0. + wxPoint m_ThirdPoint0; ///< End point for an arc. wxPoint m_Bezier0_C1; ///< Bezier Control Point 1, relative to module origin, orient 0. wxPoint m_Bezier0_C2; ///< Bezier Control Point 2, relative to module origin, orient 0. }; diff --git a/pcbnew/convert_drawsegment_list_to_polygon.cpp b/pcbnew/convert_drawsegment_list_to_polygon.cpp index 55baad4bf1..28e8e24825 100644 --- a/pcbnew/convert_drawsegment_list_to_polygon.cpp +++ b/pcbnew/convert_drawsegment_list_to_polygon.cpp @@ -178,12 +178,14 @@ static DRAWSEGMENT* findPoint( const wxPoint& aPoint, std::vector< DRAWSEGMENT* * 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 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& aSegList, SHAPE_POLY_SET& aPolygons, - wxString* aErrorText, unsigned int aTolerance, wxPoint* aErrorLocation ) + wxString* aErrorText, unsigned int aTolerance, + wxPoint* aErrorLocation ) { if( aSegList.size() == 0 ) return true; @@ -225,15 +227,12 @@ bool ConvertOutlineToPolygon( std::vector& aSegList, SHAPE_POLY_SE 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 ); + int steps = GetArcToSegmentCount( radius, aTolerance, angle / 10.0 ); wxPoint pt; for( int step = 1; step<=steps; ++step ) @@ -273,10 +272,8 @@ bool ConvertOutlineToPolygon( std::vector& aSegList, SHAPE_POLY_SE { graphic->RebuildBezierToSegmentsPointsList( graphic->GetWidth() ); - for( unsigned int jj = 0; jj < graphic->GetBezierPoints().size(); jj++ ) + for( const wxPoint& pt : graphic->GetBezierPoints()) { - wxPoint pt = graphic->GetBezierPoints()[jj]; - if( pt.x < xmin.x ) { xmin = pt; @@ -288,14 +285,14 @@ bool ConvertOutlineToPolygon( std::vector& aSegList, SHAPE_POLY_SE 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 ); + const SHAPE_POLY_SET 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; + VECTOR2I pt = *iter; RotatePoint( pt, orientation ); pt += offset; @@ -308,6 +305,7 @@ bool ConvertOutlineToPolygon( std::vector& aSegList, SHAPE_POLY_SE } } break; + default: break; } @@ -358,8 +356,10 @@ bool ConvertOutlineToPolygon( std::vector& aSegList, SHAPE_POLY_SE // Polygon start point. Arbitrarily chosen end of the // segment and build the poly from here. - wxPoint startPt = wxPoint( graphic->GetEnd() ); - prevPt = graphic->GetEnd(); + wxPoint startPt = graphic->GetShape() == S_ARC ? graphic->GetArcEnd() + : graphic->GetEnd(); + + prevPt = startPt; aPolygons.NewOutline(); aPolygons.Append( prevPt ); @@ -374,9 +374,8 @@ bool ConvertOutlineToPolygon( std::vector& aSegList, SHAPE_POLY_SE { 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. + // 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(); @@ -389,9 +388,8 @@ bool ConvertOutlineToPolygon( std::vector& aSegList, SHAPE_POLY_SE 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. + // 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(); @@ -424,12 +422,11 @@ bool ConvertOutlineToPolygon( std::vector& aSegList, SHAPE_POLY_SE 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. + // 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; + wxPoint nextPt; + bool reverse = false; // Use the end point furthest away from // prevPt as we assume the other end to be ON prevPt or @@ -584,13 +581,9 @@ bool ConvertOutlineToPolygon( std::vector& aSegList, SHAPE_POLY_SE // 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 ); @@ -660,8 +653,8 @@ bool ConvertOutlineToPolygon( std::vector& aSegList, SHAPE_POLY_SE } else { - for( size_t jj = 0; jj < graphic->GetBezierPoints().size(); jj++ ) - aPolygons.Append( graphic->GetBezierPoints()[jj], -1, hole ); + for( const wxPoint& pt : graphic->GetBezierPoints()) + aPolygons.Append( pt, -1, hole ); } prevPt = nextPt; @@ -702,8 +695,8 @@ bool ConvertOutlineToPolygon( std::vector& aSegList, SHAPE_POLY_SE if( aErrorText ) { msg.Printf( _( "Unable to find segment with an endpoint of (%s, %s)." ), - StringFromValue( EDA_UNITS::MILLIMETRES, prevPt.x, true ), - StringFromValue( EDA_UNITS::MILLIMETRES, prevPt.y, true ) ); + StringFromValue( EDA_UNITS::MILLIMETRES, prevPt.x, true ), + StringFromValue( EDA_UNITS::MILLIMETRES, prevPt.y, true ) ); *aErrorText << msg << "\n"; } @@ -742,7 +735,7 @@ bool ConvertOutlineToPolygon( std::vector& aSegList, SHAPE_POLY_SE return false; } - if( auto pt = seg1.Get().Intersect( seg2.Get(), true ) ) + if( boost::optional pt = seg1.Get().Intersect( seg2.Get(), true ) ) { if( aErrorLocation ) { diff --git a/pcbnew/legacy_plugin.cpp b/pcbnew/legacy_plugin.cpp index c61d894d82..764b5396e3 100644 --- a/pcbnew/legacy_plugin.cpp +++ b/pcbnew/legacy_plugin.cpp @@ -1678,9 +1678,12 @@ void LEGACY_PLUGIN::loadMODULE_EDGE( MODULE* aModule ) width = biuParse( data, &data ); layer = layerParse( data ); - dwg->SetAngle( angle ); dwg->m_Start0 = wxPoint( start0_x, start0_y ); dwg->m_End0 = wxPoint( end0_x, end0_y ); + + // Setting angle will set m_ThirdPoint0, so must be done after setting + // m_Start0 and m_End0 + dwg->SetAngle( angle ); } break; diff --git a/pcbnew/pcad2kicadpcb_plugin/pcb_arc.cpp b/pcbnew/pcad2kicadpcb_plugin/pcb_arc.cpp index ec2633a0c3..f8364b9491 100644 --- a/pcbnew/pcad2kicadpcb_plugin/pcb_arc.cpp +++ b/pcbnew/pcad2kicadpcb_plugin/pcb_arc.cpp @@ -163,10 +163,13 @@ void PCB_ARC::AddToModule( MODULE* aModule ) EDGE_MODULE* arc = new EDGE_MODULE( aModule, ( IsCircle() ? S_CIRCLE : S_ARC ) ); aModule->Add( arc ); - arc->SetAngle( -m_angle ); arc->m_Start0 = wxPoint( m_positionX, m_positionY ); arc->m_End0 = wxPoint( m_startX, m_startY ); + // Setting angle will set m_ThirdPoint0, so must be done after setting + // m_Start0 and m_End0 + arc->SetAngle( -m_angle ); + arc->SetWidth( m_width ); arc->SetLayer( m_KiCadLayer ); diff --git a/pcbnew/pcb_parser.cpp b/pcbnew/pcb_parser.cpp index 79383f16b7..2a3019d775 100644 --- a/pcbnew/pcb_parser.cpp +++ b/pcbnew/pcb_parser.cpp @@ -2960,6 +2960,8 @@ EDGE_MODULE* PCB_PARSER::parseEDGE_MODULE() if( token != T_angle ) Expecting( T_angle ); + // Setting angle will set m_ThirdPoint0, so must be done after setting + // m_Start0 and m_End0 segment->SetAngle( parseDouble( "segment angle" ) * 10.0 ); NeedRIGHT(); break;