From 874f13e29ea643693a714e1e4a650b9b63e3aa61 Mon Sep 17 00:00:00 2001 From: Jeff Young Date: Mon, 27 Apr 2020 17:22:42 +0100 Subject: [PATCH] Fix some issues with rotated oval pads. --- .../3d_canvas/create_3Dgraphic_brd_items.cpp | 2 +- eeschema/sch_base_frame.cpp | 16 +--- include/base_struct.h | 7 ++ ...board_items_to_polygon_shape_transform.cpp | 6 +- pcbnew/class_pad.cpp | 27 ++++--- pcbnew/class_pad.h | 14 ++-- pcbnew/class_track.h | 1 + pcbnew/drc/drc_clearance_test_functions.cpp | 74 +++++++------------ pcbnew/pcb_base_frame.cpp | 2 +- pcbnew/plot_board_layers.cpp | 3 +- 10 files changed, 66 insertions(+), 86 deletions(-) diff --git a/3d-viewer/3d_canvas/create_3Dgraphic_brd_items.cpp b/3d-viewer/3d_canvas/create_3Dgraphic_brd_items.cpp index 66c7c14818..f12d003b08 100644 --- a/3d-viewer/3d_canvas/create_3Dgraphic_brd_items.cpp +++ b/3d-viewer/3d_canvas/create_3Dgraphic_brd_items.cpp @@ -590,7 +590,7 @@ COBJECT2D *BOARD_ADAPTER::createNewPadDrill( const D_PAD* aPad, int aInflateValu wxPoint start, end; int width; - aPad->GetOblongDrillGeometry( start, end, width ); + aPad->GetOblongGeometry( aPad->GetDrillSize(), &start, &end, &width ); width += aInflateValue * 2; start += aPad->GetPosition(); diff --git a/eeschema/sch_base_frame.cpp b/eeschema/sch_base_frame.cpp index 901f2740aa..7975bf3453 100644 --- a/eeschema/sch_base_frame.cpp +++ b/eeschema/sch_base_frame.cpp @@ -360,20 +360,8 @@ void SCH_BASE_FRAME::FocusOnItem( SCH_ITEM* aItem ) RefreshItem( aItem ); lastBrightenedItemID = aItem->m_Uuid; - wxPoint position = aItem->GetPosition(); - - if( aItem->GetParent() && aItem->GetParent()->Type() == SCH_COMPONENT_T ) - { - SCH_COMPONENT* comp = static_cast( aItem->GetParent() ); - - // for a pin, GetPosition() is relative to the symbol, not rotated, not mirrored - // calculate the physical position: - wxPoint delta; - delta = comp->GetTransform().TransformCoordinate( position ); - position = delta + comp->GetPosition(); - } - - FocusOnLocation( position ); + // JEY TODO: test this with pins and fields (and with rotated symbols) .... + FocusOnLocation( aItem->GetFocusPosition() ); } } diff --git a/include/base_struct.h b/include/base_struct.h index e3b72dc871..fa83f18d26 100644 --- a/include/base_struct.h +++ b/include/base_struct.h @@ -342,6 +342,13 @@ public: virtual const wxPoint GetPosition() const { return wxPoint(); } + /** + * Function GetFocusPosition + * similar to GetPosition, but allows items to return their visual center rather + * than their anchor. + */ + virtual const wxPoint GetFocusPosition() const { return GetPosition(); } + /** * Function Clone * creates a duplicate of this item with linked list members set to NULL. diff --git a/pcbnew/board_items_to_polygon_shape_transform.cpp b/pcbnew/board_items_to_polygon_shape_transform.cpp index de8544f96a..dccdaebc42 100644 --- a/pcbnew/board_items_to_polygon_shape_transform.cpp +++ b/pcbnew/board_items_to_polygon_shape_transform.cpp @@ -679,8 +679,8 @@ void D_PAD::BuildPadShapePolygon( SHAPE_POLY_SET& aCornerBuffer, wxSize aInflate } -bool D_PAD::BuildPadDrillShapePolygon( - SHAPE_POLY_SET& aCornerBuffer, int aInflateValue, int aError ) const +bool D_PAD::BuildPadDrillShapePolygon( SHAPE_POLY_SET& aCornerBuffer, int aInflateValue, + int aError ) const { wxSize drillsize = GetDrillSize(); @@ -697,7 +697,7 @@ bool D_PAD::BuildPadDrillShapePolygon( wxPoint start, end; int width; - GetOblongDrillGeometry( start, end, width ); + GetOblongGeometry( GetDrillSize(), &start, &end, &width ); start += GetPosition(); end += GetPosition(); diff --git a/pcbnew/class_pad.cpp b/pcbnew/class_pad.cpp index be5f37212c..ffb09248da 100644 --- a/pcbnew/class_pad.cpp +++ b/pcbnew/class_pad.cpp @@ -1047,37 +1047,36 @@ void D_PAD::GetMsgPanelInfo( EDA_DRAW_FRAME* aFrame, std::vector } -void D_PAD::GetOblongDrillGeometry( wxPoint& aStartPoint, - wxPoint& aEndPoint, int& aWidth ) const +void D_PAD::GetOblongGeometry( const wxSize& aDrillOrPadSize, + wxPoint* aStartPoint, wxPoint* aEndPoint, int* aWidth ) const { // calculates the start point, end point and width - // of an equivalent segment which have the same position and width as the hole + // of an equivalent segment which have the same position and width as the pad or hole int delta_cx, delta_cy; - wxSize halfsize = GetDrillSize(); - halfsize.x /= 2; - halfsize.y /= 2; + wxSize halfsize = aDrillOrPadSize / 2; + wxPoint offset; - if( m_Drill.x > m_Drill.y ) // horizontal + if( aDrillOrPadSize.x > aDrillOrPadSize.y ) // horizontal { delta_cx = halfsize.x - halfsize.y; delta_cy = 0; - aWidth = m_Drill.y; + *aWidth = aDrillOrPadSize.y; } - else // vertical + else // vertical { delta_cx = 0; delta_cy = halfsize.y - halfsize.x; - aWidth = m_Drill.x; + *aWidth = aDrillOrPadSize.x; } RotatePoint( &delta_cx, &delta_cy, m_Orient ); - aStartPoint.x = delta_cx; - aStartPoint.y = delta_cy; + aStartPoint->x = delta_cx + offset.x; + aStartPoint->y = delta_cy + offset.y; - aEndPoint.x = - delta_cx; - aEndPoint.y = - delta_cy; + aEndPoint->x = - delta_cx + offset.x; + aEndPoint->y = - delta_cy + offset.y; } diff --git a/pcbnew/class_pad.h b/pcbnew/class_pad.h index e320c6cc15..e3cc86d3f7 100644 --- a/pcbnew/class_pad.h +++ b/pcbnew/class_pad.h @@ -408,15 +408,19 @@ public: PAD_DRILL_SHAPE_T GetDrillShape() const { return m_drillShape; } /** - * Function GetOblongDrillGeometry calculates the start point, end point and width - * of an equivalent segment which have the same position and width as the hole - * Usefull to plot/draw oblong holes like segments with rounded ends - * used in draw and plot functions + * Function GetOblongGeometry calculates the start point, end point and width of an + * equivalent segment which have the same position and width as the pad (for circular + * of oval pads) or hole + * + * NB: points returned are RELATIVE to the PAD POSITION. For board coordinates holes + * will need to be offset by GetPosition() and pads by ShapePos(). + * * @param aStartPoint = first point of the equivalent segment, relative to the pad position. * @param aEndPoint = second point of the equivalent segment, relative to the pad position. * @param aWidth = width equivalent segment. */ - void GetOblongDrillGeometry( wxPoint& aStartPoint, wxPoint& aEndPoint, int& aWidth ) const; + void GetOblongGeometry( const wxSize& aDrillOrPadSize, + wxPoint* aStartPoint, wxPoint* aEndPoint, int* aWidth ) const; void SetLayerSet( LSET aLayerMask ) { m_layerMask = aLayerMask; } LSET GetLayerSet() const override { return m_layerMask; } diff --git a/pcbnew/class_track.h b/pcbnew/class_track.h index 9e55ea929e..0763963940 100644 --- a/pcbnew/class_track.h +++ b/pcbnew/class_track.h @@ -100,6 +100,7 @@ public: void SetPosition( const wxPoint& aPos ) override { m_Start = aPos; } const wxPoint GetPosition() const override { return m_Start; } + const wxPoint GetFocusPosition() const override { return ( m_Start + m_End ) / 2; } void SetWidth( int aWidth ) { m_Width = aWidth; } int GetWidth() const { return m_Width; } diff --git a/pcbnew/drc/drc_clearance_test_functions.cpp b/pcbnew/drc/drc_clearance_test_functions.cpp index 8ca6145d8d..0ccecced03 100644 --- a/pcbnew/drc/drc_clearance_test_functions.cpp +++ b/pcbnew/drc/drc_clearance_test_functions.cpp @@ -338,21 +338,23 @@ void DRC::doTrackDrc( TRACK* aRefSeg, TRACKS::iterator aStartIt, TRACKS::iterato if( pad->GetDrillSize().x > 0 ) { + wxString clearanceSource; + int minClearance = aRefSeg->GetClearance( nullptr, &clearanceSource ); + /* Treat an oval hole as a line segment along the hole's major axis, * shortened by half its minor axis. * A circular hole is just a degenerate case of an oval hole. */ - wxPoint slotStart; - wxPoint slotEnd; + wxPoint slotStart, slotEnd; int slotWidth; - pad->GetOblongDrillGeometry( slotStart, slotEnd, slotWidth ); + pad->GetOblongGeometry( pad->GetDrillSize(), &slotStart, &slotEnd, &slotWidth ); + slotStart += pad->GetPosition(); + slotEnd += pad->GetPosition(); - wxString clearanceSource; - int minClearance = aRefSeg->GetClearance( nullptr, &clearanceSource ); - SEG slotSeg( slotStart, slotEnd ); - int widths = ( slotWidth + refSegWidth ) / 2; - int center2centerAllowed = minClearance + widths; + SEG slotSeg( slotStart, slotEnd ); + int widths = ( slotWidth + refSegWidth ) / 2; + int center2centerAllowed = minClearance + widths; // Avoid square-roots if possible (for performance) SEG::ecoord center2center_squared = refSeg.SquaredDistance( slotSeg ); @@ -387,11 +389,11 @@ void DRC::doTrackDrc( TRACK* aRefSeg, TRACKS::iterator aStartIt, TRACKS::iterato wxString clearanceSource; int minClearance = aRefSeg->GetClearance( pad, &clearanceSource ); - SEG padSeg( pad->GetPosition(), pad->GetPosition() ); int actual; if( !checkClearanceSegmToPad( refSeg, refSegWidth, pad, minClearance, &actual ) ) { + SEG padSeg( pad->GetPosition(), pad->GetPosition() ); DRC_ITEM* drcItem = new DRC_ITEM( DRCE_TRACK_NEAR_PAD ); msg.Printf( drcItem->GetErrorText() + _( " (%s %s; actual %s)" ), @@ -666,22 +668,12 @@ bool DRC::checkClearancePadToPad( D_PAD* aRefPad, D_PAD* aPad, int aMinClearance * shortened by half its minor axis. * A circular pad is just a degenerate case of an oval hole. */ - wxPoint refPadStart = aRefPad->GetPosition() + aRefPad->GetOffset(); - wxPoint refPadEnd = aRefPad->GetPosition() + aRefPad->GetOffset(); + wxPoint refPadStart, refPadEnd; int refPadWidth; - if( aRefPad->GetSize().x > aRefPad->GetSize().y ) - { - refPadWidth = aRefPad->GetSize().y; - refPadStart.x -= ( aRefPad->GetSize().x - refPadWidth ) / 2; - refPadEnd.x += ( aRefPad->GetSize().x - refPadWidth ) / 2; - } - else - { - refPadWidth = aRefPad->GetSize().x; - refPadStart.y -= ( aRefPad->GetSize().y - refPadWidth ) / 2; - refPadEnd.y += ( aRefPad->GetSize().y - refPadWidth ) / 2; - } + aRefPad->GetOblongGeometry( aRefPad->GetSize(), &refPadStart, &refPadEnd, &refPadWidth ); + refPadStart += aRefPad->ShapePos(); + refPadEnd += aRefPad->ShapePos(); SEG refPadSeg( refPadStart, refPadEnd ); diag = checkClearanceSegmToPad( refPadSeg, refPadWidth, aPad, aMinClearance, aActual ); @@ -694,14 +686,6 @@ bool DRC::checkClearancePadToPad( D_PAD* aRefPad, D_PAD* aPad, int aMinClearance wxPoint polyref[4]; // corners of aRefPad (used only for custom pad) SHAPE_POLY_SET polysetref; - // corners of aPad (used only for rect/roundrect/trap pad) - wxPoint polycompare[4]; - // corners of aPad (used only custom pad) - SHAPE_POLY_SET polysetcompare; - - // pad_angle = pad orient relative to the aRefPad orient - double pad_angle = aRefPad->GetOrientation() + aPad->GetOrientation(); - NORMALIZE_ANGLE_POS( pad_angle ); if( aRefPad->GetShape() == PAD_SHAPE_ROUNDRECT ) { @@ -739,6 +723,11 @@ bool DRC::checkClearancePadToPad( D_PAD* aRefPad, D_PAD* aPad, int aMinClearance aRefPad->BuildPadPolygon( polyref, wxSize( 0, 0 ), aRefPad->GetOrientation() ); } + // corners of aPad (used only for rect/roundrect/trap pad) + wxPoint polycompare[4]; + // corners of aPad (used only custom pad) + SHAPE_POLY_SET polysetcompare; + switch( aPad->GetShape() ) { case PAD_SHAPE_ROUNDRECT: @@ -784,6 +773,7 @@ bool DRC::checkClearancePadToPad( D_PAD* aRefPad, D_PAD* aPad, int aMinClearance for( int ii = 0; ii < 4; ii++ ) polycompare[ii] += relativePadPos; } + // And now test polygons: We have 3 cases: // one poly is complex and the other is basic (has only 4 corners) // both polys are complex @@ -857,25 +847,15 @@ bool DRC::checkClearanceSegmToPad( const SEG& refSeg, int refSegWidth, const D_P * shortened by half its minor axis. * A circular pad is just a degenerate case of an oval hole. */ - wxPoint padStart = pad->GetPosition() + pad->GetOffset(); // JEY TODO: needs to handle rotation.... - wxPoint padEnd = pad->GetPosition() + pad->GetOffset(); - int padHalfWidth; + wxPoint padStart, padEnd; + int padWidth; - if( pad->GetSize().x > pad->GetSize().y ) - { - padHalfWidth = pad->GetSize().y / 2; - padStart.x -= ( pad->GetSize().x / 2 ) - padHalfWidth; - padEnd.x += ( pad->GetSize().x / 2 ) - padHalfWidth; - } - else - { - padHalfWidth = pad->GetSize().x / 2; - padStart.y -= ( pad->GetSize().y / 2 ) - padHalfWidth; - padEnd.y += ( pad->GetSize().y / 2 ) - padHalfWidth; - } + pad->GetOblongGeometry( pad->GetSize(), &padStart, &padEnd, &padWidth ); + padStart += pad->ShapePos(); + padEnd += pad->ShapePos(); SEG padSeg( padStart, padEnd ); - int widths = padHalfWidth + ( refSegWidth / 2 ); + int widths = ( padWidth + refSegWidth ) / 2; int center2centerAllowed = minClearance + widths; // Avoid square-roots if possible (for performance) diff --git a/pcbnew/pcb_base_frame.cpp b/pcbnew/pcb_base_frame.cpp index fdb4956cc6..f94df80014 100644 --- a/pcbnew/pcb_base_frame.cpp +++ b/pcbnew/pcb_base_frame.cpp @@ -230,7 +230,7 @@ void PCB_BASE_FRAME::FocusOnItem( BOARD_ITEM* aItem ) GetCanvas()->GetView()->Update( aItem ); lastBrightenedItemID = aItem->m_Uuid; - FocusOnLocation( aItem->GetPosition() ); + FocusOnLocation( aItem->GetFocusPosition() ); GetCanvas()->Refresh(); } } diff --git a/pcbnew/plot_board_layers.cpp b/pcbnew/plot_board_layers.cpp index 62dcd907e6..105fd81e60 100644 --- a/pcbnew/plot_board_layers.cpp +++ b/pcbnew/plot_board_layers.cpp @@ -779,7 +779,8 @@ void PlotLayerOutlines( BOARD* aBoard, PLOTTER* aPlotter, LSET aLayerMask, // Note: small drill marks have no significance when applied to slots wxPoint drl_start, drl_end; int width; - pad->GetOblongDrillGeometry( drl_start, drl_end, width ); + + pad->GetOblongGeometry( pad->GetDrillSize(), &drl_start, &drl_end, &width ); aPlotter->ThickSegment( pad->GetPosition() + drl_start, pad->GetPosition() + drl_end, width, SKETCH, NULL ); }