mirror of
https://gitlab.com/kicad/code/kicad.git
synced 2025-04-11 14:50:11 +00:00
Pcbnew/FPedit: Add snap anchor type indicators
This allows to see what the current snap point is, which is useful when zoomed in, or the point is like the corner of a rounded pad where it's "in free space" and might not be immediately obvious.
This commit is contained in:
parent
410e200f80
commit
0818ee1770
common
include
libs/kimath
pcbnew/tools
qa/tests/libs/kimath/geometry
@ -449,6 +449,7 @@ set( COMMON_PREVIEW_ITEMS_SRCS
|
||||
preview_items/ruler_item.cpp
|
||||
preview_items/selection_area.cpp
|
||||
preview_items/simple_overlay_item.cpp
|
||||
preview_items/snap_indicator.cpp
|
||||
preview_items/two_point_assistant.cpp
|
||||
)
|
||||
|
||||
|
158
common/preview_items/snap_indicator.cpp
Normal file
158
common/preview_items/snap_indicator.cpp
Normal file
@ -0,0 +1,158 @@
|
||||
/*
|
||||
* This program source code file is part of KiCad, a free EDA CAD application.
|
||||
*
|
||||
* Copyright (C) 20204 KiCad Developers, see AUTHORS.txt for contributors.
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU General Public License
|
||||
* as published by the Free Software Foundation; either version 2
|
||||
* of the License, or (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program; if not, you may find one here:
|
||||
* http://www.gnu.org/licenses/old-licenses/gpl-2.0.html
|
||||
* or you may search the http://www.gnu.org website for the version 2 license,
|
||||
* or you may write to the Free Software Foundation, Inc.,
|
||||
* 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA
|
||||
*/
|
||||
|
||||
#include <preview_items/snap_indicator.h>
|
||||
|
||||
#include <gal/graphics_abstraction_layer.h>
|
||||
|
||||
using namespace KIGFX;
|
||||
|
||||
SNAP_INDICATOR::SNAP_INDICATOR( const COLOR4D& aColor, int aSize, const VECTOR2D& aPosition ) :
|
||||
ORIGIN_VIEWITEM( aColor, CIRCLE_CROSS, aSize, aPosition )
|
||||
{
|
||||
}
|
||||
|
||||
|
||||
SNAP_INDICATOR* SNAP_INDICATOR::Clone() const
|
||||
{
|
||||
return new SNAP_INDICATOR( m_color, m_size, m_position );
|
||||
}
|
||||
|
||||
|
||||
const BOX2I SNAP_INDICATOR::ViewBBox() const
|
||||
{
|
||||
return ORIGIN_VIEWITEM::ViewBBox();
|
||||
}
|
||||
|
||||
|
||||
static void DrawSnapNode( GAL& aGal, const VECTOR2I& aPosition, int aNodeRadius )
|
||||
{
|
||||
aGal.SetIsFill( true );
|
||||
aGal.SetIsStroke( false );
|
||||
|
||||
aGal.DrawCircle( aPosition, aNodeRadius );
|
||||
|
||||
aGal.SetIsFill( false );
|
||||
aGal.SetIsStroke( true );
|
||||
}
|
||||
|
||||
|
||||
static void DrawCornerIcon( GAL& aGal, const VECTOR2I& aPosition, int aSize )
|
||||
{
|
||||
const int nodeRad = aSize / 8;
|
||||
const VECTOR2I corner =
|
||||
aPosition - VECTOR2I( aSize / 2, aSize / 2 ) + VECTOR2I( nodeRad, nodeRad );
|
||||
aGal.DrawLine( corner, corner + VECTOR2I( aSize - nodeRad, 0 ) );
|
||||
aGal.DrawLine( corner, corner + VECTOR2I( 0, aSize - nodeRad ) );
|
||||
|
||||
DrawSnapNode( aGal, corner, nodeRad );
|
||||
}
|
||||
|
||||
static void DrawLineEndpointIcon( GAL& aGal, const VECTOR2I& aPosition, int aSize )
|
||||
{
|
||||
const int nodeRadius = aSize / 8;
|
||||
const VECTOR2I lineStart = aPosition - VECTOR2I( aSize / 2 - nodeRadius, 0 );
|
||||
|
||||
DrawSnapNode( aGal, lineStart, nodeRadius );
|
||||
aGal.DrawLine( lineStart, lineStart + VECTOR2I( aSize - nodeRadius, 0 ) );
|
||||
}
|
||||
|
||||
static void DrawMidpointIcon( GAL& aGal, const VECTOR2I& aPosition, int aSize )
|
||||
{
|
||||
const int nodeRadius = aSize / 8;
|
||||
|
||||
DrawSnapNode( aGal, aPosition, nodeRadius );
|
||||
aGal.DrawLine( aPosition - VECTOR2I( aSize / 2, 0 ), aPosition + VECTOR2I( aSize / 2, 0 ) );
|
||||
}
|
||||
|
||||
static void DrawCentrePointIcon( GAL& aGal, const VECTOR2I& aPosition, int aSize )
|
||||
{
|
||||
const int ringRadius = aSize / 4;
|
||||
|
||||
aGal.DrawCircle( aPosition, ringRadius );
|
||||
|
||||
aGal.DrawLine( aPosition - VECTOR2I( aSize / 2, 0 ), aPosition + VECTOR2I( aSize / 2, 0 ) );
|
||||
aGal.DrawLine( aPosition - VECTOR2I( 0, aSize / 2 ), aPosition + VECTOR2I( 0, aSize / 2 ) );
|
||||
}
|
||||
|
||||
static void DrawQuadrantPointIcon( GAL& aGal, const VECTOR2I& aPosition, int aSize )
|
||||
{
|
||||
const int nodeRadius = aSize / 8;
|
||||
|
||||
const VECTOR2I quadPoint = aPosition - VECTOR2I( 0, aSize / 2 - nodeRadius );
|
||||
const int arcRadius = aSize - nodeRadius * 2;
|
||||
|
||||
DrawSnapNode( aGal, quadPoint, nodeRadius );
|
||||
|
||||
// Most of the top half of a circle, passing through the node centre
|
||||
const VECTOR2I arcCenter = quadPoint + VECTOR2I( 0, arcRadius );
|
||||
aGal.DrawArc( arcCenter, arcRadius, EDA_ANGLE( -160, EDA_ANGLE_T::DEGREES_T ),
|
||||
EDA_ANGLE( 140, EDA_ANGLE_T::DEGREES_T ) );
|
||||
}
|
||||
|
||||
|
||||
void SNAP_INDICATOR::ViewDraw( int, VIEW* aView ) const
|
||||
{
|
||||
GAL& gal = *aView->GetGAL();
|
||||
|
||||
// Draw the origin marker
|
||||
ORIGIN_VIEWITEM::ViewDraw( 0, aView );
|
||||
|
||||
gal.SetFillColor( m_color );
|
||||
|
||||
const auto scaleSize = [&]( double aSize ) -> int
|
||||
{
|
||||
return aView->ToWorld( aSize );
|
||||
};
|
||||
|
||||
const auto scaleVec = [&]( const VECTOR2I& aVec ) -> VECTOR2I
|
||||
{
|
||||
return aView->ToWorld( aVec, false );
|
||||
};
|
||||
|
||||
// Put the icon near the x-line, so it doesn't overlap with the ruler helpers
|
||||
const VECTOR2I typeIconPos = m_position + scaleVec( { 24, 10 } );
|
||||
const int size = scaleSize( 16 );
|
||||
|
||||
// For now, choose the first type that is set
|
||||
if( m_snapTypes & POINT_TYPE::PT_CORNER )
|
||||
{
|
||||
DrawCornerIcon( gal, typeIconPos, size );
|
||||
}
|
||||
else if( m_snapTypes & POINT_TYPE::PT_END )
|
||||
{
|
||||
DrawLineEndpointIcon( gal, typeIconPos, size );
|
||||
}
|
||||
else if( m_snapTypes & POINT_TYPE::PT_MID )
|
||||
{
|
||||
DrawMidpointIcon( gal, typeIconPos, size );
|
||||
}
|
||||
else if( m_snapTypes & POINT_TYPE::PT_CENTER )
|
||||
{
|
||||
DrawCentrePointIcon( gal, typeIconPos, size );
|
||||
}
|
||||
else if( m_snapTypes & POINT_TYPE::PT_QUADRANT )
|
||||
{
|
||||
DrawQuadrantPointIcon( gal, typeIconPos, size );
|
||||
}
|
||||
}
|
76
include/preview_items/snap_indicator.h
Normal file
76
include/preview_items/snap_indicator.h
Normal file
@ -0,0 +1,76 @@
|
||||
/*
|
||||
* This program source code file is part of KiCad, a free EDA CAD application.
|
||||
*
|
||||
* Copyright (C) 2024 KiCad Developers, see AUTHORS.txt for contributors.
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU General Public License
|
||||
* as published by the Free Software Foundation; either version 2
|
||||
* of the License, or (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program; if not, you may find one here:
|
||||
* http://www.gnu.org/licenses/old-licenses/gpl-2.0.html
|
||||
* or you may search the http://www.gnu.org website for the version 2 license,
|
||||
* or you may write to the Free Software Foundation, Inc.,
|
||||
* 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA
|
||||
*/
|
||||
|
||||
#ifndef __SNAP_INDICATOR_H
|
||||
#define __SNAP_INDICATOR_H
|
||||
|
||||
#include <origin_viewitem.h>
|
||||
#include <geometry/point_types.h>
|
||||
|
||||
|
||||
namespace KIGFX
|
||||
{
|
||||
|
||||
/**
|
||||
* View item to draw an origin marker with an optional
|
||||
* snap type indicator.
|
||||
*/
|
||||
class SNAP_INDICATOR : public ORIGIN_VIEWITEM
|
||||
{
|
||||
public:
|
||||
SNAP_INDICATOR( const COLOR4D& aColor = COLOR4D::WHITE, int aSize = 16,
|
||||
const VECTOR2D& aPosition = VECTOR2D( 0, 0 ) );
|
||||
|
||||
SNAP_INDICATOR( const VECTOR2D& aPosition, EDA_ITEM_FLAGS flags );
|
||||
|
||||
SNAP_INDICATOR* Clone() const override;
|
||||
|
||||
const BOX2I ViewBBox() const override;
|
||||
|
||||
void ViewDraw( int aLayer, VIEW* aView ) const override;
|
||||
|
||||
#if defined( DEBUG )
|
||||
void Show( int x, std::ostream& st ) const override {}
|
||||
#endif
|
||||
|
||||
/**
|
||||
* Get class name.
|
||||
*
|
||||
* @return string "SNAP_INDICATOR"
|
||||
*/
|
||||
wxString GetClass() const override { return wxT( "SNAP_INDICATOR" ); }
|
||||
|
||||
/**
|
||||
* Set a mask of point types that this snap item represents.
|
||||
*
|
||||
* This is a mask of POINT_TYPE.
|
||||
*/
|
||||
void SetSnapTypes( int aSnapTypes ) { m_snapTypes = aSnapTypes; }
|
||||
|
||||
private:
|
||||
int m_snapTypes = POINT_TYPE::PT_NONE;
|
||||
};
|
||||
|
||||
} // namespace KIGFX
|
||||
|
||||
#endif
|
@ -24,13 +24,15 @@
|
||||
#ifndef GRID_HELPER_H
|
||||
#define GRID_HELPER_H
|
||||
|
||||
#include "tool/selection.h"
|
||||
#include <tool/tool_manager.h>
|
||||
#include <vector>
|
||||
|
||||
#include <geometry/point_types.h>
|
||||
#include <math/vector2d.h>
|
||||
#include <preview_items/snap_indicator.h>
|
||||
#include <tool/tool_manager.h>
|
||||
#include <tool/selection.h>
|
||||
#include <origin_viewitem.h>
|
||||
|
||||
class TOOL_MANAGER;
|
||||
class EDA_ITEM;
|
||||
|
||||
enum GRID_HELPER_GRIDS : int
|
||||
@ -117,7 +119,8 @@ public:
|
||||
|
||||
std::optional<VECTOR2I> GetSnappedPoint() const;
|
||||
|
||||
enum ANCHOR_FLAGS {
|
||||
enum ANCHOR_FLAGS
|
||||
{
|
||||
CORNER = 1,
|
||||
OUTLINE = 2,
|
||||
SNAPPABLE = 4,
|
||||
@ -131,14 +134,23 @@ protected:
|
||||
|
||||
struct ANCHOR
|
||||
{
|
||||
ANCHOR( const VECTOR2I& aPos, int aFlags = CORNER | SNAPPABLE, EDA_ITEM* aItem = nullptr ) :
|
||||
pos( aPos ),
|
||||
flags( aFlags ),
|
||||
item( aItem )
|
||||
{ };
|
||||
/**
|
||||
*
|
||||
* @param aPos The position of the anchor
|
||||
* @param aFlags The flags for the anchor - this is a bitfield of ANCHOR_FLAGS,
|
||||
* specifying the type of anchor (which may be used to filter out
|
||||
* unwanted anchors per the settings)
|
||||
* @param aPointTypes The point types that this anchor represents in geometric terms
|
||||
* @param aItem The item to which the anchor belongs
|
||||
*/
|
||||
ANCHOR( const VECTOR2I& aPos, int aFlags, int aPointTypes, EDA_ITEM* aItem ) :
|
||||
pos( aPos ), flags( aFlags ), pointTypes( aPointTypes ), item( aItem )
|
||||
{
|
||||
}
|
||||
|
||||
VECTOR2I pos;
|
||||
int flags;
|
||||
int pointTypes;
|
||||
EDA_ITEM* item;
|
||||
|
||||
double Distance( const VECTOR2I& aP ) const
|
||||
@ -147,10 +159,11 @@ protected:
|
||||
}
|
||||
};
|
||||
|
||||
void addAnchor( const VECTOR2I& aPos, int aFlags, EDA_ITEM* aItem )
|
||||
void addAnchor( const VECTOR2I& aPos, int aFlags, EDA_ITEM* aItem,
|
||||
int aPointTypes = POINT_TYPE::PT_NONE )
|
||||
{
|
||||
if( ( aFlags & m_maskTypes ) == aFlags )
|
||||
m_anchors.emplace_back( ANCHOR( aPos, aFlags, aItem ) );
|
||||
m_anchors.emplace_back( ANCHOR( aPos, aFlags, aPointTypes, aItem ) );
|
||||
}
|
||||
|
||||
void clearAnchors()
|
||||
@ -182,7 +195,7 @@ protected:
|
||||
// (NULL if not snapped)
|
||||
VECTOR2I m_skipPoint; // When drawing a line, we avoid snapping to the
|
||||
// source point
|
||||
KIGFX::ORIGIN_VIEWITEM m_viewSnapPoint;
|
||||
KIGFX::SNAP_INDICATOR m_viewSnapPoint;
|
||||
KIGFX::ORIGIN_VIEWITEM m_viewSnapLine;
|
||||
KIGFX::ORIGIN_VIEWITEM m_viewAxis;
|
||||
};
|
||||
|
@ -28,6 +28,7 @@
|
||||
|
||||
#include <math/vector2d.h>
|
||||
#include <geometry/eda_angle.h>
|
||||
#include <geometry/point_types.h>
|
||||
|
||||
enum OVAL_KEY_POINTS
|
||||
{
|
||||
@ -55,9 +56,9 @@ using OVAL_KEY_POINT_FLAGS = unsigned int;
|
||||
* @param aRotation - The rotation of the oval
|
||||
* @param aFlags - The flags indicating which points to return
|
||||
*
|
||||
* @return std::vector<VECTOR2I> - The list of points
|
||||
* @return std::vector<TYPED_POINT2I> - The list of points and their geomtrical types
|
||||
*/
|
||||
std::vector<VECTOR2I> GetOvalKeyPoints( const VECTOR2I& aOvalSize, const EDA_ANGLE& aRotation,
|
||||
OVAL_KEY_POINT_FLAGS aFlags );
|
||||
std::vector<TYPED_POINT2I> GetOvalKeyPoints( const VECTOR2I& aOvalSize, const EDA_ANGLE& aRotation,
|
||||
OVAL_KEY_POINT_FLAGS aFlags );
|
||||
|
||||
#endif /* GEOMETRY_OVAL_H_ */
|
77
libs/kimath/include/geometry/point_types.h
Normal file
77
libs/kimath/include/geometry/point_types.h
Normal file
@ -0,0 +1,77 @@
|
||||
/*
|
||||
* This program source code file is part of KiCad, a free EDA CAD application.
|
||||
*
|
||||
* Copyright (C) 2023 KiCad Developers, see AUTHORS.txt for contributors.
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU General Public License
|
||||
* as published by the Free Software Foundation; either version 2
|
||||
* of the License, or (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program; if not, you may find one here:
|
||||
* http://www.gnu.org/licenses/old-licenses/gpl-2.0.html
|
||||
* or you may search the http://www.gnu.org website for the version 2 license,
|
||||
* or you may write to the Free Software Foundation, Inc.,
|
||||
* 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA
|
||||
*/
|
||||
|
||||
#ifndef GEOMETRY_POINT_TYPE_H_
|
||||
#define GEOMETRY_POINT_TYPE_H_
|
||||
|
||||
#include <math/vector2d.h>
|
||||
|
||||
/**
|
||||
* Meanings that can be assigned to a point in pure geometric
|
||||
* terms.
|
||||
*
|
||||
* For example, a circle has a center point and four quadrant points.
|
||||
*
|
||||
* These can be combined using bitwise OR if a point has multiple meanings.
|
||||
*/
|
||||
enum POINT_TYPE
|
||||
{
|
||||
/**
|
||||
* No specific point type.
|
||||
*/
|
||||
PT_NONE = 0,
|
||||
/**
|
||||
* The point is the center of something.
|
||||
*/
|
||||
PT_CENTER = 1 << 0,
|
||||
/**
|
||||
* The point is at the end of a segment, arc, etc.
|
||||
*/
|
||||
PT_END = 1 << 1,
|
||||
/**
|
||||
* The point is at the middle of a segment, arc, etc.
|
||||
*/
|
||||
PT_MID = 1 << 2,
|
||||
/**
|
||||
* The point is on a quadrant of a circle (N, E, S, W points).
|
||||
*/
|
||||
PT_QUADRANT = 1 << 3,
|
||||
/**
|
||||
* The point is a corner of a polygon, rectangle, etc
|
||||
* (you may want to infer PT_END from this)
|
||||
*/
|
||||
PT_CORNER = 1 << 4,
|
||||
};
|
||||
|
||||
struct TYPED_POINT2I
|
||||
{
|
||||
VECTOR2I m_point;
|
||||
POINT_TYPE m_types;
|
||||
|
||||
// Clang needs this apparently
|
||||
TYPED_POINT2I( const VECTOR2I& aVec, POINT_TYPE aTypes ) : m_point( aVec ), m_types( aTypes ) {}
|
||||
|
||||
bool operator==( const TYPED_POINT2I& ) const = default;
|
||||
};
|
||||
|
||||
#endif // GEOMETRY_POINT_TYPE_H_
|
@ -28,8 +28,8 @@
|
||||
#include <trigo.h> // for RotatePoint
|
||||
|
||||
|
||||
std::vector<VECTOR2I> GetOvalKeyPoints( const VECTOR2I& aOvalSize, const EDA_ANGLE& aRotation,
|
||||
OVAL_KEY_POINT_FLAGS aFlags )
|
||||
std::vector<TYPED_POINT2I> GetOvalKeyPoints( const VECTOR2I& aOvalSize, const EDA_ANGLE& aRotation,
|
||||
OVAL_KEY_POINT_FLAGS aFlags )
|
||||
{
|
||||
const VECTOR2I half_size = aOvalSize / 2;
|
||||
const int half_width = std::min( half_size.x, half_size.y );
|
||||
@ -37,26 +37,29 @@ std::vector<VECTOR2I> GetOvalKeyPoints( const VECTOR2I& aOvalSize, const EDA_ANG
|
||||
|
||||
// Points on a non-rotated pad at the origin, long-axis is y
|
||||
// (so for now, width is left/right, len is up/down)
|
||||
std::vector<VECTOR2I> pts;
|
||||
std::vector<TYPED_POINT2I> pts;
|
||||
|
||||
if ( aFlags & OVAL_CENTER )
|
||||
{
|
||||
// Centre is easy
|
||||
pts.emplace_back( 0, 0 );
|
||||
pts.emplace_back( VECTOR2I{ 0, 0 }, POINT_TYPE::PT_CENTER );
|
||||
};
|
||||
|
||||
if ( aFlags & OVAL_SIDE_MIDPOINTS )
|
||||
if( aFlags & OVAL_SIDE_MIDPOINTS )
|
||||
{
|
||||
// Side midpoints
|
||||
pts.emplace_back( half_width, 0 );
|
||||
pts.emplace_back( -half_width, 0 );
|
||||
pts.emplace_back( VECTOR2I{ half_width, 0 }, POINT_TYPE::PT_MID );
|
||||
pts.emplace_back( VECTOR2I{ -half_width, 0 }, POINT_TYPE::PT_MID );
|
||||
}
|
||||
|
||||
if ( aFlags & OVAL_CAP_TIPS )
|
||||
if( aFlags & OVAL_CAP_TIPS )
|
||||
{
|
||||
// If the oval is square-on, the tips are quadrants
|
||||
const POINT_TYPE pt_type = aRotation.IsCardinal() ? PT_QUADRANT : PT_END;
|
||||
|
||||
// Cap ends
|
||||
pts.emplace_back( 0, half_len );
|
||||
pts.emplace_back( 0, -half_len );
|
||||
pts.emplace_back( VECTOR2I{ 0, half_len }, pt_type );
|
||||
pts.emplace_back( VECTOR2I{ 0, -half_len }, pt_type );
|
||||
}
|
||||
|
||||
// Distance from centre to cap centres
|
||||
@ -65,17 +68,22 @@ std::vector<VECTOR2I> GetOvalKeyPoints( const VECTOR2I& aOvalSize, const EDA_ANG
|
||||
if ( aFlags & OVAL_CAP_CENTERS )
|
||||
{
|
||||
// Cap centres
|
||||
pts.emplace_back( 0, d_centre_to_cap_centre );
|
||||
pts.emplace_back( 0, -d_centre_to_cap_centre );
|
||||
pts.emplace_back( VECTOR2I{ 0, d_centre_to_cap_centre }, POINT_TYPE::PT_CENTER );
|
||||
pts.emplace_back( VECTOR2I{ 0, -d_centre_to_cap_centre }, POINT_TYPE::PT_CENTER );
|
||||
}
|
||||
|
||||
if ( aFlags & OVAL_SIDE_ENDS )
|
||||
{
|
||||
const auto add_end = [&]( const VECTOR2I& aPt )
|
||||
{
|
||||
pts.emplace_back( aPt, POINT_TYPE::PT_END );
|
||||
};
|
||||
|
||||
// End points of flat sides (always vertical)
|
||||
pts.emplace_back( half_width, d_centre_to_cap_centre );
|
||||
pts.emplace_back( half_width, -d_centre_to_cap_centre );
|
||||
pts.emplace_back( -half_width, d_centre_to_cap_centre );
|
||||
pts.emplace_back( -half_width, -d_centre_to_cap_centre );
|
||||
add_end( { half_width, d_centre_to_cap_centre } );
|
||||
add_end( { half_width, -d_centre_to_cap_centre } );
|
||||
add_end( { -half_width, d_centre_to_cap_centre } );
|
||||
add_end( { -half_width, -d_centre_to_cap_centre } );
|
||||
}
|
||||
|
||||
// If the pad is horizontal (i.e. x > y), we'll rotate the whole thing
|
||||
@ -115,19 +123,24 @@ std::vector<VECTOR2I> GetOvalKeyPoints( const VECTOR2I& aOvalSize, const EDA_ANG
|
||||
VECTOR2I cap_radial_to_y_axis = cap_radial;
|
||||
RotatePoint( cap_radial_to_y_axis, radial_line_rotation );
|
||||
|
||||
const auto add_quadrant = [&]( const VECTOR2I& aPt )
|
||||
{
|
||||
pts.emplace_back( aPt, POINT_TYPE::PT_QUADRANT );
|
||||
};
|
||||
|
||||
// The quadrant points are then the relevant offsets from each cap centre
|
||||
pts.emplace_back( VECTOR2I{ 0, d_centre_to_cap_centre } + cap_radial_to_y_axis );
|
||||
pts.emplace_back( VECTOR2I{ 0, d_centre_to_cap_centre } + cap_radial_to_x_axis );
|
||||
add_quadrant( VECTOR2I{ 0, d_centre_to_cap_centre } + cap_radial_to_y_axis );
|
||||
add_quadrant( VECTOR2I{ 0, d_centre_to_cap_centre } + cap_radial_to_x_axis );
|
||||
// The opposite cap offsets go from the other cap centre, the other way
|
||||
pts.emplace_back( VECTOR2I{ 0, -d_centre_to_cap_centre } - cap_radial_to_y_axis );
|
||||
pts.emplace_back( VECTOR2I{ 0, -d_centre_to_cap_centre } - cap_radial_to_x_axis );
|
||||
add_quadrant( VECTOR2I{ 0, -d_centre_to_cap_centre } - cap_radial_to_y_axis );
|
||||
add_quadrant( VECTOR2I{ 0, -d_centre_to_cap_centre } - cap_radial_to_x_axis );
|
||||
}
|
||||
|
||||
for( VECTOR2I& pt : pts )
|
||||
for( TYPED_POINT2I& pt : pts )
|
||||
{
|
||||
// Transform to the actual orientation
|
||||
// Already includes the extra 90 to swap x/y if needed
|
||||
RotatePoint( pt, rotation );
|
||||
RotatePoint( pt.m_point, rotation );
|
||||
}
|
||||
|
||||
return pts;
|
||||
|
@ -65,6 +65,7 @@ PCB_GRID_HELPER::PCB_GRID_HELPER( TOOL_MANAGER* aToolMgr, MAGNETIC_SETTINGS* aMa
|
||||
view->Add( &m_viewAxis );
|
||||
view->SetVisible( &m_viewAxis, false );
|
||||
|
||||
m_viewSnapPoint.SetSize( 10 );
|
||||
m_viewSnapPoint.SetStyle( KIGFX::ORIGIN_VIEWITEM::CIRCLE_CROSS );
|
||||
m_viewSnapPoint.SetColor( auxItemsColor );
|
||||
m_viewSnapPoint.SetDrawAtZero( true );
|
||||
@ -289,7 +290,6 @@ VECTOR2I PCB_GRID_HELPER::BestSnapAnchor( const VECTOR2I& aOrigin, BOARD_ITEM* a
|
||||
return BestSnapAnchor( aOrigin, layers, aGrid, item );
|
||||
}
|
||||
|
||||
|
||||
VECTOR2I PCB_GRID_HELPER::BestSnapAnchor( const VECTOR2I& aOrigin, const LSET& aLayers,
|
||||
GRID_HELPER_GRIDS aGrid,
|
||||
const std::vector<BOARD_ITEM*>& aSkip )
|
||||
@ -365,6 +365,8 @@ VECTOR2I PCB_GRID_HELPER::BestSnapAnchor( const VECTOR2I& aOrigin, const LSET& a
|
||||
m_viewSnapLine.SetPosition( nearest->pos );
|
||||
m_toolMgr->GetView()->SetVisible( &m_viewSnapLine, false );
|
||||
|
||||
m_viewSnapPoint.SetSnapTypes( nearest->pointTypes );
|
||||
|
||||
if( m_toolMgr->GetView()->IsVisible( &m_viewSnapPoint ) )
|
||||
m_toolMgr->GetView()->Update( &m_viewSnapPoint, KIGFX::GEOMETRY);
|
||||
else
|
||||
@ -579,124 +581,126 @@ void PCB_GRID_HELPER::computeAnchors( BOARD_ITEM* aItem, const VECTOR2I& aRefPos
|
||||
| OVAL_CARDINAL_EXTREMES;
|
||||
|
||||
// The key points of a circle centred around (0, 0) with the given radius
|
||||
auto getCircleKeyPoints =
|
||||
[]( int radius )
|
||||
auto getCircleKeyPoints = []( int radius, bool aIncludeCenter )
|
||||
{
|
||||
std::vector<TYPED_POINT2I> points = {
|
||||
{ { -radius, 0 }, POINT_TYPE::PT_QUADRANT },
|
||||
{ { radius, 0 }, POINT_TYPE::PT_QUADRANT },
|
||||
{ { 0, -radius }, POINT_TYPE::PT_QUADRANT },
|
||||
{ { 0, radius }, POINT_TYPE::PT_QUADRANT },
|
||||
};
|
||||
|
||||
if( aIncludeCenter )
|
||||
points.push_back( { { 0, 0 }, POINT_TYPE::PT_CENTER } );
|
||||
|
||||
return points;
|
||||
};
|
||||
|
||||
auto handlePadShape = [&]( PAD* aPad )
|
||||
{
|
||||
addAnchor( aPad->GetPosition(), ORIGIN | SNAPPABLE, aPad, POINT_TYPE::PT_CENTER );
|
||||
|
||||
/// If we are getting a drag point, we don't want to center the edge of pads
|
||||
if( aFrom )
|
||||
return;
|
||||
|
||||
switch( aPad->GetShape() )
|
||||
{
|
||||
case PAD_SHAPE::CIRCLE:
|
||||
for( const TYPED_POINT2I& pt : getCircleKeyPoints( aPad->GetSizeX() / 2, false ) )
|
||||
{
|
||||
return std::vector<VECTOR2I>{ { 0, 0 },
|
||||
{ -radius, 0 },
|
||||
{ radius, 0 },
|
||||
{ 0, -radius },
|
||||
{ 0, radius } };
|
||||
};
|
||||
// Transform to the pad positon
|
||||
addAnchor( aPad->ShapePos() + pt.m_point, OUTLINE | SNAPPABLE, aPad, pt.m_types );
|
||||
}
|
||||
|
||||
auto handlePadShape =
|
||||
[&]( PAD* aPad )
|
||||
break;
|
||||
|
||||
case PAD_SHAPE::OVAL:
|
||||
for( const TYPED_POINT2I& pt :
|
||||
GetOvalKeyPoints( aPad->GetSize(), aPad->GetOrientation(), ovalKeyPointFlags ) )
|
||||
{
|
||||
addAnchor( aPad->GetPosition(), ORIGIN | SNAPPABLE, aPad );
|
||||
// Transform to the pad positon
|
||||
addAnchor( aPad->ShapePos() + pt.m_point, OUTLINE | SNAPPABLE, aPad, pt.m_types );
|
||||
}
|
||||
|
||||
/// If we are getting a drag point, we don't want to center the edge of pads
|
||||
if( aFrom )
|
||||
return;
|
||||
break;
|
||||
|
||||
switch( aPad->GetShape() )
|
||||
{
|
||||
case PAD_SHAPE::CIRCLE:
|
||||
for( const VECTOR2I& pt: getCircleKeyPoints( aPad->GetSizeX() / 2 ) )
|
||||
{
|
||||
// Transform to the pad positon
|
||||
addAnchor( aPad->ShapePos() + pt, OUTLINE | SNAPPABLE, aPad );
|
||||
}
|
||||
case PAD_SHAPE::RECTANGLE:
|
||||
case PAD_SHAPE::TRAPEZOID:
|
||||
case PAD_SHAPE::ROUNDRECT:
|
||||
case PAD_SHAPE::CHAMFERED_RECT:
|
||||
{
|
||||
VECTOR2I half_size( aPad->GetSize() / 2 );
|
||||
VECTOR2I trap_delta( 0, 0 );
|
||||
|
||||
break;
|
||||
if( aPad->GetShape() == PAD_SHAPE::TRAPEZOID )
|
||||
trap_delta = aPad->GetDelta() / 2;
|
||||
|
||||
case PAD_SHAPE::OVAL:
|
||||
for( const VECTOR2I& pt: GetOvalKeyPoints( aPad->GetSize(),
|
||||
aPad->GetOrientation(),
|
||||
ovalKeyPointFlags ) )
|
||||
{
|
||||
// Transform to the pad positon
|
||||
addAnchor( aPad->ShapePos() + pt, OUTLINE | SNAPPABLE, aPad );
|
||||
}
|
||||
SHAPE_LINE_CHAIN corners;
|
||||
|
||||
break;
|
||||
corners.Append( -half_size.x - trap_delta.y, half_size.y + trap_delta.x );
|
||||
corners.Append( half_size.x + trap_delta.y, half_size.y - trap_delta.x );
|
||||
corners.Append( half_size.x - trap_delta.y, -half_size.y + trap_delta.x );
|
||||
corners.Append( -half_size.x + trap_delta.y, -half_size.y - trap_delta.x );
|
||||
corners.SetClosed( true );
|
||||
|
||||
case PAD_SHAPE::RECTANGLE:
|
||||
case PAD_SHAPE::TRAPEZOID:
|
||||
case PAD_SHAPE::ROUNDRECT:
|
||||
case PAD_SHAPE::CHAMFERED_RECT:
|
||||
{
|
||||
VECTOR2I half_size( aPad->GetSize() / 2 );
|
||||
VECTOR2I trap_delta( 0, 0 );
|
||||
corners.Rotate( aPad->GetOrientation() );
|
||||
corners.Move( aPad->ShapePos() );
|
||||
|
||||
if( aPad->GetShape() == PAD_SHAPE::TRAPEZOID )
|
||||
trap_delta = aPad->GetDelta() / 2;
|
||||
for( size_t ii = 0; ii < corners.GetSegmentCount(); ++ii )
|
||||
{
|
||||
const SEG& seg = corners.GetSegment( ii );
|
||||
addAnchor( seg.A, OUTLINE | SNAPPABLE, aPad, POINT_TYPE::PT_CORNER );
|
||||
addAnchor( seg.Center(), OUTLINE | SNAPPABLE, aPad, POINT_TYPE::PT_MID );
|
||||
|
||||
SHAPE_LINE_CHAIN corners;
|
||||
if( ii == corners.GetSegmentCount() - 1 )
|
||||
addAnchor( seg.B, OUTLINE | SNAPPABLE, aPad, POINT_TYPE::PT_CORNER );
|
||||
}
|
||||
|
||||
corners.Append( -half_size.x - trap_delta.y, half_size.y + trap_delta.x );
|
||||
corners.Append( half_size.x + trap_delta.y, half_size.y - trap_delta.x );
|
||||
corners.Append( half_size.x - trap_delta.y, -half_size.y + trap_delta.x );
|
||||
corners.Append( -half_size.x + trap_delta.y, -half_size.y - trap_delta.x );
|
||||
corners.SetClosed( true );
|
||||
break;
|
||||
}
|
||||
|
||||
corners.Rotate( aPad->GetOrientation() );
|
||||
corners.Move( aPad->ShapePos() );
|
||||
default:
|
||||
{
|
||||
const auto& outline = aPad->GetEffectivePolygon( ERROR_INSIDE );
|
||||
|
||||
for( size_t ii = 0; ii < corners.GetSegmentCount(); ++ii )
|
||||
{
|
||||
const SEG& seg = corners.GetSegment( ii );
|
||||
addAnchor( seg.A, OUTLINE | SNAPPABLE, aPad );
|
||||
addAnchor( seg.Center(), OUTLINE | SNAPPABLE, aPad );
|
||||
if( !outline->IsEmpty() )
|
||||
{
|
||||
for( const VECTOR2I& pt : outline->Outline( 0 ).CPoints() )
|
||||
addAnchor( pt, OUTLINE | SNAPPABLE, aPad );
|
||||
}
|
||||
|
||||
if( ii == corners.GetSegmentCount() - 1 )
|
||||
addAnchor( seg.B, OUTLINE | SNAPPABLE, aPad );
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
break;
|
||||
}
|
||||
if( aPad->HasHole() )
|
||||
{
|
||||
// Holes are at the pad centre (it's the shape that may be offset)
|
||||
const VECTOR2I hole_pos = aPad->GetPosition();
|
||||
const VECTOR2I hole_size = aPad->GetDrillSize();
|
||||
|
||||
default:
|
||||
{
|
||||
const auto& outline = aPad->GetEffectivePolygon( ERROR_INSIDE );
|
||||
std::vector<TYPED_POINT2I> snap_pts;
|
||||
|
||||
if( !outline->IsEmpty() )
|
||||
{
|
||||
for( const VECTOR2I& pt : outline->Outline( 0 ).CPoints() )
|
||||
addAnchor( pt, OUTLINE | SNAPPABLE, aPad );
|
||||
}
|
||||
if( hole_size.x == hole_size.y )
|
||||
{
|
||||
// Circle
|
||||
snap_pts = getCircleKeyPoints( hole_size.x / 2, true );
|
||||
}
|
||||
else
|
||||
{
|
||||
// Oval
|
||||
|
||||
break;
|
||||
}
|
||||
}
|
||||
// For now there's no way to have an off-angle hole, so this is the
|
||||
// same as the pad. In future, this may not be true:
|
||||
// https://gitlab.com/kicad/code/kicad/-/issues/4124
|
||||
snap_pts = GetOvalKeyPoints( hole_size, aPad->GetOrientation(), ovalKeyPointFlags );
|
||||
}
|
||||
|
||||
if( aPad->HasHole() )
|
||||
{
|
||||
// Holes are at the pad centre (it's the shape that may be offset)
|
||||
const VECTOR2I hole_pos = aPad->GetPosition();
|
||||
const VECTOR2I hole_size = aPad->GetDrillSize();
|
||||
|
||||
std::vector<VECTOR2I> snap_pts;
|
||||
|
||||
if ( hole_size.x == hole_size.y )
|
||||
{
|
||||
// Circle
|
||||
snap_pts = getCircleKeyPoints( hole_size.x / 2 );
|
||||
}
|
||||
else
|
||||
{
|
||||
// Oval
|
||||
|
||||
// For now there's no way to have an off-angle hole, so this is the
|
||||
// same as the pad. In future, this may not be true:
|
||||
// https://gitlab.com/kicad/code/kicad/-/issues/4124
|
||||
snap_pts = GetOvalKeyPoints( hole_size, aPad->GetOrientation(),
|
||||
ovalKeyPointFlags );
|
||||
}
|
||||
|
||||
for( const VECTOR2I& snap_pt : snap_pts )
|
||||
addAnchor( hole_pos + snap_pt, OUTLINE | SNAPPABLE, aPad );
|
||||
}
|
||||
};
|
||||
for( const TYPED_POINT2I& snap_pt : snap_pts )
|
||||
addAnchor( hole_pos + snap_pt.m_point, OUTLINE | SNAPPABLE, aPad, snap_pt.m_types );
|
||||
}
|
||||
};
|
||||
|
||||
auto handleShape =
|
||||
[&]( PCB_SHAPE* shape )
|
||||
@ -708,21 +712,30 @@ void PCB_GRID_HELPER::computeAnchors( BOARD_ITEM* aItem, const VECTOR2I& aRefPos
|
||||
{
|
||||
case SHAPE_T::CIRCLE:
|
||||
{
|
||||
int r = ( start - end ).EuclideanNorm();
|
||||
const int r = ( start - end ).EuclideanNorm();
|
||||
|
||||
addAnchor( start, ORIGIN | SNAPPABLE, shape );
|
||||
addAnchor( start + VECTOR2I( -r, 0 ), OUTLINE | SNAPPABLE, shape );
|
||||
addAnchor( start + VECTOR2I( r, 0 ), OUTLINE | SNAPPABLE, shape );
|
||||
addAnchor( start + VECTOR2I( 0, -r ), OUTLINE | SNAPPABLE, shape );
|
||||
addAnchor( start + VECTOR2I( 0, r ), OUTLINE | SNAPPABLE, shape );
|
||||
addAnchor( start, ORIGIN | SNAPPABLE, shape, POINT_TYPE::PT_CENTER );
|
||||
|
||||
addAnchor( start + VECTOR2I( -r, 0 ), OUTLINE | SNAPPABLE, shape,
|
||||
POINT_TYPE::PT_QUADRANT );
|
||||
addAnchor( start + VECTOR2I( r, 0 ), OUTLINE | SNAPPABLE, shape,
|
||||
POINT_TYPE::PT_QUADRANT );
|
||||
addAnchor( start + VECTOR2I( 0, -r ), OUTLINE | SNAPPABLE, shape,
|
||||
POINT_TYPE::PT_QUADRANT );
|
||||
addAnchor( start + VECTOR2I( 0, r ), OUTLINE | SNAPPABLE, shape,
|
||||
POINT_TYPE::PT_QUADRANT );
|
||||
break;
|
||||
}
|
||||
|
||||
case SHAPE_T::ARC:
|
||||
addAnchor( shape->GetStart(), CORNER | SNAPPABLE, shape );
|
||||
addAnchor( shape->GetEnd(), CORNER | SNAPPABLE, shape );
|
||||
addAnchor( shape->GetArcMid(), CORNER | SNAPPABLE, shape );
|
||||
addAnchor( shape->GetCenter(), ORIGIN | SNAPPABLE, shape );
|
||||
addAnchor( shape->GetStart(), CORNER | SNAPPABLE, shape,
|
||||
POINT_TYPE::PT_END );
|
||||
addAnchor( shape->GetEnd(), CORNER | SNAPPABLE, shape,
|
||||
POINT_TYPE::PT_CORNER );
|
||||
addAnchor( shape->GetArcMid(), CORNER | SNAPPABLE, shape,
|
||||
POINT_TYPE::PT_MID );
|
||||
addAnchor( shape->GetCenter(), ORIGIN | SNAPPABLE, shape,
|
||||
POINT_TYPE::PT_CENTER );
|
||||
break;
|
||||
|
||||
case SHAPE_T::RECTANGLE:
|
||||
@ -734,21 +747,24 @@ void PCB_GRID_HELPER::computeAnchors( BOARD_ITEM* aItem, const VECTOR2I& aRefPos
|
||||
SEG third( end, point3 );
|
||||
SEG fourth( point3, start );
|
||||
|
||||
addAnchor( first.A, CORNER | SNAPPABLE, shape );
|
||||
addAnchor( first.Center(), CORNER | SNAPPABLE, shape );
|
||||
addAnchor( second.A, CORNER | SNAPPABLE, shape );
|
||||
addAnchor( second.Center(), CORNER | SNAPPABLE, shape );
|
||||
addAnchor( third.A, CORNER | SNAPPABLE, shape );
|
||||
addAnchor( third.Center(), CORNER | SNAPPABLE, shape );
|
||||
addAnchor( fourth.A, CORNER | SNAPPABLE, shape );
|
||||
addAnchor( fourth.Center(), CORNER | SNAPPABLE, shape );
|
||||
const int snapFlags = CORNER | SNAPPABLE;
|
||||
|
||||
addAnchor( first.A, snapFlags, shape, POINT_TYPE::PT_CORNER );
|
||||
addAnchor( first.Center(), snapFlags, shape, POINT_TYPE::PT_MID );
|
||||
addAnchor( second.A, snapFlags, shape, POINT_TYPE::PT_CORNER );
|
||||
addAnchor( second.Center(), snapFlags, shape, POINT_TYPE::PT_MID );
|
||||
addAnchor( third.A, snapFlags, shape, POINT_TYPE::PT_CORNER );
|
||||
addAnchor( third.Center(), snapFlags, shape, POINT_TYPE::PT_MID );
|
||||
addAnchor( fourth.A, snapFlags, shape, POINT_TYPE::PT_CORNER );
|
||||
addAnchor( fourth.Center(), snapFlags, shape, POINT_TYPE::PT_MID );
|
||||
break;
|
||||
}
|
||||
|
||||
case SHAPE_T::SEGMENT:
|
||||
addAnchor( start, CORNER | SNAPPABLE, shape );
|
||||
addAnchor( end, CORNER | SNAPPABLE, shape );
|
||||
addAnchor( shape->GetCenter(), CORNER | SNAPPABLE, shape );
|
||||
addAnchor( start, CORNER | SNAPPABLE, shape, POINT_TYPE::PT_END );
|
||||
addAnchor( end, CORNER | SNAPPABLE, shape, POINT_TYPE::PT_END );
|
||||
addAnchor( shape->GetCenter(), CORNER | SNAPPABLE, shape,
|
||||
POINT_TYPE::PT_MID );
|
||||
break;
|
||||
|
||||
case SHAPE_T::POLY:
|
||||
@ -760,7 +776,7 @@ void PCB_GRID_HELPER::computeAnchors( BOARD_ITEM* aItem, const VECTOR2I& aRefPos
|
||||
|
||||
for( const VECTOR2I& p : poly )
|
||||
{
|
||||
addAnchor( p, CORNER | SNAPPABLE, shape );
|
||||
addAnchor( p, CORNER | SNAPPABLE, shape, POINT_TYPE::PT_CORNER );
|
||||
lc.Append( p );
|
||||
}
|
||||
|
||||
@ -769,8 +785,8 @@ void PCB_GRID_HELPER::computeAnchors( BOARD_ITEM* aItem, const VECTOR2I& aRefPos
|
||||
}
|
||||
|
||||
case SHAPE_T::BEZIER:
|
||||
addAnchor( start, CORNER | SNAPPABLE, shape );
|
||||
addAnchor( end, CORNER | SNAPPABLE, shape );
|
||||
addAnchor( start, CORNER | SNAPPABLE, shape, POINT_TYPE::PT_END );
|
||||
addAnchor( end, CORNER | SNAPPABLE, shape, POINT_TYPE::PT_END );
|
||||
KI_FALLTHROUGH;
|
||||
|
||||
default:
|
||||
@ -817,10 +833,10 @@ void PCB_GRID_HELPER::computeAnchors( BOARD_ITEM* aItem, const VECTOR2I& aRefPos
|
||||
VECTOR2I grid( GetGrid() );
|
||||
|
||||
if( view->IsLayerVisible( LAYER_ANCHOR ) )
|
||||
addAnchor( position, ORIGIN | SNAPPABLE, footprint );
|
||||
addAnchor( position, ORIGIN | SNAPPABLE, footprint, POINT_TYPE::PT_CENTER );
|
||||
|
||||
if( ( center - position ).SquaredEuclideanNorm() > grid.SquaredEuclideanNorm() )
|
||||
addAnchor( center, ORIGIN | SNAPPABLE, footprint );
|
||||
addAnchor( center, ORIGIN | SNAPPABLE, footprint, POINT_TYPE::PT_CENTER );
|
||||
|
||||
break;
|
||||
}
|
||||
@ -893,16 +909,17 @@ void PCB_GRID_HELPER::computeAnchors( BOARD_ITEM* aItem, const VECTOR2I& aRefPos
|
||||
{
|
||||
PCB_TRACK* track = static_cast<PCB_TRACK*>( aItem );
|
||||
|
||||
addAnchor( track->GetStart(), CORNER | SNAPPABLE, track );
|
||||
addAnchor( track->GetEnd(), CORNER | SNAPPABLE, track );
|
||||
addAnchor( track->GetCenter(), ORIGIN, track);
|
||||
addAnchor( track->GetStart(), CORNER | SNAPPABLE, track, POINT_TYPE::PT_END );
|
||||
addAnchor( track->GetEnd(), CORNER | SNAPPABLE, track, POINT_TYPE::PT_END );
|
||||
addAnchor( track->GetCenter(), ORIGIN, track, POINT_TYPE::PT_MID );
|
||||
}
|
||||
|
||||
break;
|
||||
|
||||
case PCB_MARKER_T:
|
||||
case PCB_TARGET_T:
|
||||
addAnchor( aItem->GetPosition(), ORIGIN | CORNER | SNAPPABLE, aItem );
|
||||
addAnchor( aItem->GetPosition(), ORIGIN | CORNER | SNAPPABLE, aItem,
|
||||
POINT_TYPE::PT_CENTER );
|
||||
break;
|
||||
|
||||
case PCB_VIA_T:
|
||||
@ -918,7 +935,8 @@ void PCB_GRID_HELPER::computeAnchors( BOARD_ITEM* aItem, const VECTOR2I& aRefPos
|
||||
}
|
||||
|
||||
if( checkVisibility( aItem ) )
|
||||
addAnchor( aItem->GetPosition(), ORIGIN | CORNER | SNAPPABLE, aItem );
|
||||
addAnchor( aItem->GetPosition(), ORIGIN | CORNER | SNAPPABLE, aItem,
|
||||
POINT_TYPE::PT_CENTER );
|
||||
|
||||
break;
|
||||
|
||||
@ -935,7 +953,7 @@ void PCB_GRID_HELPER::computeAnchors( BOARD_ITEM* aItem, const VECTOR2I& aRefPos
|
||||
|
||||
for( auto iter = outline->CIterateWithHoles(); iter; iter++ )
|
||||
{
|
||||
addAnchor( *iter, CORNER | SNAPPABLE, aItem );
|
||||
addAnchor( *iter, CORNER | SNAPPABLE, aItem, POINT_TYPE::PT_CORNER );
|
||||
lc.Append( *iter );
|
||||
}
|
||||
|
||||
|
@ -15,3 +15,29 @@ std::ostream& boost_test_print_type( std::ostream& os, const SHAPE_LINE_CHAIN& c
|
||||
os << "]";
|
||||
return os;
|
||||
}
|
||||
|
||||
std::string toString( const POINT_TYPE& aType )
|
||||
{
|
||||
switch( aType )
|
||||
{
|
||||
case PT_NONE: return "PT_NONE";
|
||||
case PT_CENTER: return "PT_CENTER";
|
||||
case PT_END: return "PT_END";
|
||||
case PT_MID: return "PT_MID";
|
||||
case PT_QUADRANT: return "PT_QUADRANT";
|
||||
case PT_CORNER: return "PT_CORNER";
|
||||
default: return "Unknown POINT_TYPE: " + std::to_string( (int) aType );
|
||||
}
|
||||
}
|
||||
|
||||
std::ostream& operator<<( std::ostream& os, const POINT_TYPE& aPtType )
|
||||
{
|
||||
os << "POINT_TYPE: " << toString( aPtType );
|
||||
return os;
|
||||
}
|
||||
|
||||
std::ostream& operator<<( std::ostream& os, const TYPED_POINT2I& aPt )
|
||||
{
|
||||
os << "TYPED_POINT2I: " << aPt.m_point << " (" << toString( aPt.m_types ) << ")";
|
||||
return os;
|
||||
}
|
@ -26,6 +26,7 @@
|
||||
|
||||
#include <cmath>
|
||||
|
||||
#include <geometry/point_types.h>
|
||||
#include <geometry/seg.h>
|
||||
#include <geometry/shape_line_chain.h>
|
||||
#include <geometry/shape_poly_set.h>
|
||||
@ -352,5 +353,9 @@ inline bool SegmentsHaveSameEndPoints( const SEG& aSeg1, const SEG& aSeg2 )
|
||||
|
||||
std::ostream& boost_test_print_type( std::ostream& os, const SHAPE_LINE_CHAIN& c );
|
||||
|
||||
// Not clear why boost_test_print_type doesn't work on Debian specifically for this type,
|
||||
// but this works on all platforms
|
||||
std::ostream& operator<<( std::ostream& os, const TYPED_POINT2I& c );
|
||||
std::ostream& operator<<( std::ostream& os, const POINT_TYPE& c );
|
||||
|
||||
#endif // GEOM_TEST_UTILS_H
|
||||
|
@ -21,7 +21,7 @@
|
||||
* 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA
|
||||
*/
|
||||
|
||||
#include <boost/test/unit_test.hpp>
|
||||
#include <qa_utils/wx_utils/unit_test_utils.h>
|
||||
|
||||
#include <geometry/oval.h>
|
||||
|
||||
@ -65,7 +65,7 @@ struct OVAL_POINTS_TEST_CASE
|
||||
{
|
||||
VECTOR2I m_size;
|
||||
EDA_ANGLE m_rotation;
|
||||
std::vector<VECTOR2I> m_expected_points;
|
||||
std::vector<TYPED_POINT2I> m_expected_points;
|
||||
};
|
||||
|
||||
void DoOvalPointTestChecks( const OVAL_POINTS_TEST_CASE& testcase )
|
||||
@ -74,8 +74,8 @@ void DoOvalPointTestChecks( const OVAL_POINTS_TEST_CASE& testcase )
|
||||
return LexicographicalCompare<VECTOR2I::coord_type>( a, b ) > 0;
|
||||
};
|
||||
|
||||
std::vector<VECTOR2I> expected_points = testcase.m_expected_points;
|
||||
std::vector<VECTOR2I> actual_points =
|
||||
std::vector<TYPED_POINT2I> expected_points = testcase.m_expected_points;
|
||||
std::vector<TYPED_POINT2I> actual_points =
|
||||
GetOvalKeyPoints( testcase.m_size, testcase.m_rotation, OVAL_ALL_KEY_POINTS );
|
||||
|
||||
CHECK_COLLECTIONS_SAME_UNORDERED( expected_points, actual_points );
|
||||
@ -88,20 +88,21 @@ BOOST_AUTO_TEST_CASE( SimpleOvalVertical )
|
||||
{ 1000, 3000 },
|
||||
{ 0, DEGREES_T },
|
||||
{
|
||||
{ 0, 0 },
|
||||
{ { 0, 0 }, PT_CENTER },
|
||||
// Main points
|
||||
{ 0, 1500 },
|
||||
{ 0, -1500 },
|
||||
{ 500, 0 },
|
||||
{ -500, 0 },
|
||||
{ { 0, 1500 }, PT_QUADRANT },
|
||||
{ { 0, -1500 }, PT_QUADRANT },
|
||||
{ { 500, 0 }, PT_MID },
|
||||
{ { -500, 0 }, PT_MID },
|
||||
// Cap centres
|
||||
{ 0, 1000 },
|
||||
{ 0, -1000 },
|
||||
{ { 0, 1000 }, PT_CENTER },
|
||||
{ { 0, -1000 }, PT_CENTER },
|
||||
// Side segment ends
|
||||
{ 500, 1000 },
|
||||
{ 500, -1000 },
|
||||
{ -500, 1000 },
|
||||
{ -500, -1000 },
|
||||
{ { 500, 1000 }, PT_END },
|
||||
{ { 500, -1000 }, PT_END },
|
||||
{ { -500, 1000 }, PT_END },
|
||||
{ { -500, -1000 }, PT_END },
|
||||
// No quadrants
|
||||
},
|
||||
};
|
||||
|
||||
@ -115,20 +116,21 @@ BOOST_AUTO_TEST_CASE( SimpleOvalHorizontal )
|
||||
{ 3000, 1000 },
|
||||
{ 0, DEGREES_T },
|
||||
{
|
||||
{ 0, 0 },
|
||||
{ { 0, 0 }, PT_CENTER },
|
||||
// Main points
|
||||
{ 0, 500 },
|
||||
{ 0, -500 },
|
||||
{ 1500, 0 },
|
||||
{ -1500, 0 },
|
||||
{ { 0, 500 }, PT_MID },
|
||||
{ { 0, -500 }, PT_MID },
|
||||
{ { 1500, 0 }, PT_QUADRANT },
|
||||
{ { -1500, 0 }, PT_QUADRANT },
|
||||
// Cap centres
|
||||
{ 1000, 0 },
|
||||
{ -1000, 0 },
|
||||
{ { 1000, 0 }, PT_CENTER },
|
||||
{ { -1000, 0 }, PT_CENTER },
|
||||
// Side segment ends
|
||||
{ 1000, 500 },
|
||||
{ 1000, -500 },
|
||||
{ -1000, 500 },
|
||||
{ -1000, -500 },
|
||||
{ { 1000, 500 }, PT_END },
|
||||
{ { 1000, -500 }, PT_END },
|
||||
{ { -1000, 500 }, PT_END },
|
||||
{ { -1000, -500 }, PT_END },
|
||||
// No quadrants
|
||||
},
|
||||
};
|
||||
|
||||
@ -149,25 +151,25 @@ BOOST_AUTO_TEST_CASE( SimpleOval45Degrees )
|
||||
{ 4000, 1000 },
|
||||
{ 45, DEGREES_T },
|
||||
{
|
||||
{ 0, 0 },
|
||||
{ { 0, 0 }, PT_CENTER },
|
||||
// Main points
|
||||
{ 1414, -1414 },
|
||||
{ -1414, 1414 },
|
||||
{ 354, 354 },
|
||||
{ -354, -354 },
|
||||
{ { 1414, -1414 }, PT_END },
|
||||
{ { -1414, 1414 }, PT_END },
|
||||
{ { 354, 354 }, PT_MID },
|
||||
{ { -354, -354 }, PT_MID },
|
||||
// Side segment ends
|
||||
{ -1414, 707 },
|
||||
{ 1414, -707 },
|
||||
{ -707, 1414 },
|
||||
{ 707, -1414 },
|
||||
{ { -1414, 707 }, PT_END },
|
||||
{ { 1414, -707 }, PT_END },
|
||||
{ { -707, 1414 }, PT_END },
|
||||
{ { 707, -1414 }, PT_END },
|
||||
// Cap centres
|
||||
{ 1061, -1061 },
|
||||
{ -1061, 1061 },
|
||||
{ { 1061, -1061 }, PT_CENTER },
|
||||
{ { -1061, 1061 }, PT_CENTER },
|
||||
// Extremum points (always one of NSEW of a cap centre because 45 degrees)
|
||||
{ -1061 - 500, 1061 },
|
||||
{ -1061, 1061 + 500 },
|
||||
{ 1061 + 500, -1061 },
|
||||
{ 1061, -1061 - 500 },
|
||||
{ { -1061 - 500, 1061 }, PT_QUADRANT },
|
||||
{ { -1061, 1061 + 500 }, PT_QUADRANT },
|
||||
{ { 1061 + 500, -1061 }, PT_QUADRANT },
|
||||
{ { 1061, -1061 - 500 }, PT_QUADRANT },
|
||||
},
|
||||
};
|
||||
|
||||
|
Loading…
Reference in New Issue
Block a user