Move HV45 to suggestions when moving
Snap lines shown when snapped
This commit is contained in:
@@ -1746,6 +1746,8 @@ void CAIRO_GAL_BASE::DrawGrid()
|
||||
return;
|
||||
|
||||
VECTOR2D gridScreenSize( m_gridSize );
|
||||
gridScreenSize = VECTOR2D( std::max( 1.0, gridScreenSize.x ),
|
||||
std::max( 1.0, gridScreenSize.y ) );
|
||||
|
||||
double gridThreshold = KiROUND( computeMinGridSpacing() / m_worldScale );
|
||||
|
||||
|
||||
@@ -76,6 +76,8 @@ GAL::GAL( GAL_DISPLAY_OPTIONS& aDisplayOptions ) :
|
||||
SetCoarseGrid( 10 );
|
||||
m_gridLineWidth = 0.5f;
|
||||
m_gridStyle = GRID_STYLE::LINES;
|
||||
m_gridSize = VECTOR2D( 1.0, 1.0 );
|
||||
m_gridOffset = VECTOR2D( 0.0, 0.0 );
|
||||
m_gridMinSpacing = 10;
|
||||
|
||||
// Initialize the cursor shape
|
||||
|
||||
@@ -24,6 +24,7 @@
|
||||
#include "preview_items/construction_geom.h"
|
||||
|
||||
#include <layer_ids.h>
|
||||
#include <utility>
|
||||
#include <gal/graphics_abstraction_layer.h>
|
||||
#include <geometry/shape_utils.h>
|
||||
#include <preview_items/item_drawing_utils.h>
|
||||
@@ -39,9 +40,15 @@ CONSTRUCTION_GEOM::CONSTRUCTION_GEOM() :
|
||||
}
|
||||
|
||||
|
||||
void CONSTRUCTION_GEOM::AddDrawable( const DRAWABLE& aItem, bool aPersistent )
|
||||
void CONSTRUCTION_GEOM::AddDrawable( const DRAWABLE& aItem, bool aPersistent, int aLineWidth )
|
||||
{
|
||||
m_drawables.push_back( { aItem, aPersistent } );
|
||||
m_drawables.push_back( { aItem, aPersistent, aLineWidth } );
|
||||
}
|
||||
|
||||
|
||||
void CONSTRUCTION_GEOM::SetSnapGuides( std::vector<SNAP_GUIDE> aGuides )
|
||||
{
|
||||
m_snapGuides = std::move( aGuides );
|
||||
}
|
||||
|
||||
|
||||
@@ -90,6 +97,7 @@ void CONSTRUCTION_GEOM::ViewDraw( int aLayer, VIEW* aView ) const
|
||||
for( const DRAWABLE_INFO& drawable : m_drawables )
|
||||
{
|
||||
gal.SetStrokeColor( drawable.IsPersistent ? m_persistentColor : m_color );
|
||||
gal.SetLineWidth( drawable.LineWidth );
|
||||
|
||||
std::visit(
|
||||
[&]( const auto& visited )
|
||||
@@ -139,9 +147,17 @@ void CONSTRUCTION_GEOM::ViewDraw( int aLayer, VIEW* aView ) const
|
||||
drawable.Item );
|
||||
}
|
||||
|
||||
for( const SNAP_GUIDE& guide : m_snapGuides )
|
||||
{
|
||||
gal.SetStrokeColor( guide.Color );
|
||||
gal.SetLineWidth( guide.LineWidth );
|
||||
gal.DrawLine( guide.Segment.A, guide.Segment.B );
|
||||
}
|
||||
|
||||
if( haveSnapLine )
|
||||
{
|
||||
gal.SetStrokeColor( m_persistentColor );
|
||||
gal.SetLineWidth( 2 );
|
||||
|
||||
const int dashSizeBasis = aView->ToWorld( 12 );
|
||||
const int snapOriginMarkerSize = aView->ToWorld( 16 );
|
||||
|
||||
@@ -23,11 +23,18 @@
|
||||
|
||||
#include "tool/construction_manager.h"
|
||||
|
||||
#include <algorithm>
|
||||
#include <chrono>
|
||||
#include <cmath>
|
||||
#include <limits>
|
||||
#include <numeric>
|
||||
#include <utility>
|
||||
|
||||
#include <wx/timer.h>
|
||||
#include <wx/debug.h>
|
||||
|
||||
#include <advanced_config.h>
|
||||
#include <math/util.h>
|
||||
#include <hash.h>
|
||||
|
||||
|
||||
@@ -329,9 +336,9 @@ void CONSTRUCTION_MANAGER::acceptConstructionItems( std::unique_ptr<PENDING_BATC
|
||||
{
|
||||
for( const CONSTRUCTION_ITEM& item : batch )
|
||||
{
|
||||
for( const KIGFX::CONSTRUCTION_GEOM::DRAWABLE& drawable : item.Constructions )
|
||||
for( const CONSTRUCTION_ITEM::DRAWABLE_ENTRY& drawable : item.Constructions )
|
||||
{
|
||||
geom.AddDrawable( drawable, aIsPersistent );
|
||||
geom.AddDrawable( drawable.Drawable, aIsPersistent, drawable.LineWidth );
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -383,16 +390,111 @@ bool CONSTRUCTION_MANAGER::HasActiveConstruction() const
|
||||
|
||||
|
||||
SNAP_LINE_MANAGER::SNAP_LINE_MANAGER( CONSTRUCTION_VIEW_HANDLER& aViewHandler ) :
|
||||
m_viewHandler( aViewHandler )
|
||||
m_viewHandler( aViewHandler ), m_snapManager( static_cast<SNAP_MANAGER*>( &aViewHandler ) )
|
||||
{
|
||||
wxASSERT( m_snapManager );
|
||||
SetDirections( { VECTOR2I( 1, 0 ), VECTOR2I( 0, 1 ) } );
|
||||
}
|
||||
|
||||
|
||||
static VECTOR2I normalizeDirection( const VECTOR2I& aDir )
|
||||
{
|
||||
if( aDir.x == 0 && aDir.y == 0 )
|
||||
return VECTOR2I( 0, 0 );
|
||||
|
||||
int dx = aDir.x;
|
||||
int dy = aDir.y;
|
||||
|
||||
int gcd = std::gcd( std::abs( dx ), std::abs( dy ) );
|
||||
|
||||
if( gcd > 0 )
|
||||
{
|
||||
dx /= gcd;
|
||||
dy /= gcd;
|
||||
}
|
||||
|
||||
if( dx < 0 || ( dx == 0 && dy < 0 ) )
|
||||
{
|
||||
dx = -dx;
|
||||
dy = -dy;
|
||||
}
|
||||
|
||||
return VECTOR2I( dx, dy );
|
||||
}
|
||||
|
||||
|
||||
static std::optional<int> findDirectionIndex( const std::vector<VECTOR2I>& aDirections,
|
||||
const VECTOR2I& aDelta )
|
||||
{
|
||||
VECTOR2I normalized = normalizeDirection( aDelta );
|
||||
|
||||
if( normalized.x == 0 && normalized.y == 0 )
|
||||
return std::nullopt;
|
||||
|
||||
for( size_t i = 0; i < aDirections.size(); ++i )
|
||||
{
|
||||
if( aDirections[i] == normalized )
|
||||
return static_cast<int>( i );
|
||||
}
|
||||
|
||||
return std::nullopt;
|
||||
}
|
||||
|
||||
|
||||
void SNAP_LINE_MANAGER::SetDirections( const std::vector<VECTOR2I>& aDirections )
|
||||
{
|
||||
std::vector<VECTOR2I> uniqueDirections;
|
||||
uniqueDirections.reserve( aDirections.size() );
|
||||
|
||||
for( const VECTOR2I& direction : aDirections )
|
||||
{
|
||||
VECTOR2I normalized = normalizeDirection( direction );
|
||||
|
||||
if( normalized.x == 0 && normalized.y == 0 )
|
||||
continue;
|
||||
|
||||
if( std::find( uniqueDirections.begin(), uniqueDirections.end(), normalized )
|
||||
== uniqueDirections.end() )
|
||||
{
|
||||
uniqueDirections.push_back( normalized );
|
||||
}
|
||||
}
|
||||
|
||||
if( uniqueDirections != m_directions )
|
||||
{
|
||||
m_directions = std::move( uniqueDirections );
|
||||
m_activeDirection.reset();
|
||||
|
||||
if( m_snapLineOrigin && m_snapLineEnd )
|
||||
{
|
||||
if( !findDirectionIndex( m_directions, *m_snapLineEnd - *m_snapLineOrigin ) )
|
||||
m_snapLineEnd.reset();
|
||||
}
|
||||
|
||||
if( m_directions.empty() )
|
||||
{
|
||||
ClearSnapLine();
|
||||
return;
|
||||
}
|
||||
|
||||
notifyGuideChange();
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
void SNAP_LINE_MANAGER::SetSnapLineOrigin( const VECTOR2I& aOrigin )
|
||||
{
|
||||
// Setting the origin clears the snap line as the end point is no longer valid
|
||||
ClearSnapLine();
|
||||
if( m_snapLineOrigin && *m_snapLineOrigin == aOrigin && !m_snapLineEnd )
|
||||
{
|
||||
notifyGuideChange();
|
||||
return;
|
||||
}
|
||||
|
||||
m_snapLineOrigin = aOrigin;
|
||||
m_snapLineEnd.reset();
|
||||
m_activeDirection.reset();
|
||||
m_viewHandler.GetViewItem().ClearSnapLine();
|
||||
notifyGuideChange();
|
||||
}
|
||||
|
||||
|
||||
@@ -402,12 +504,17 @@ void SNAP_LINE_MANAGER::SetSnapLineEnd( const OPT_VECTOR2I& aSnapEnd )
|
||||
{
|
||||
m_snapLineEnd = aSnapEnd;
|
||||
|
||||
if( m_snapLineEnd )
|
||||
m_activeDirection = findDirectionIndex( m_directions, *m_snapLineEnd - *m_snapLineOrigin );
|
||||
else
|
||||
m_activeDirection.reset();
|
||||
|
||||
if( m_snapLineEnd )
|
||||
m_viewHandler.GetViewItem().SetSnapLine( SEG{ *m_snapLineOrigin, *m_snapLineEnd } );
|
||||
else
|
||||
m_viewHandler.GetViewItem().ClearSnapLine();
|
||||
|
||||
m_viewHandler.updateView();
|
||||
notifyGuideChange();
|
||||
}
|
||||
}
|
||||
|
||||
@@ -416,8 +523,9 @@ void SNAP_LINE_MANAGER::ClearSnapLine()
|
||||
{
|
||||
m_snapLineOrigin.reset();
|
||||
m_snapLineEnd.reset();
|
||||
m_activeDirection.reset();
|
||||
m_viewHandler.GetViewItem().ClearSnapLine();
|
||||
m_viewHandler.updateView();
|
||||
notifyGuideChange();
|
||||
}
|
||||
|
||||
|
||||
@@ -425,7 +533,7 @@ void SNAP_LINE_MANAGER::SetSnappedAnchor( const VECTOR2I& aAnchorPos )
|
||||
{
|
||||
if( m_snapLineOrigin.has_value() )
|
||||
{
|
||||
if( aAnchorPos.x == m_snapLineOrigin->x || aAnchorPos.y == m_snapLineOrigin->y )
|
||||
if( findDirectionIndex( m_directions, aAnchorPos - *m_snapLineOrigin ) )
|
||||
{
|
||||
SetSnapLineEnd( aAnchorPos );
|
||||
}
|
||||
@@ -444,93 +552,86 @@ void SNAP_LINE_MANAGER::SetSnappedAnchor( const VECTOR2I& aAnchorPos )
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Check if the cursor has moved far enough away from the snap line origin to escape snapping
|
||||
* in the X direction.
|
||||
*
|
||||
* This is defined as within aEscapeRange of the snap line origin, and within aLongRangeEscapeAngle
|
||||
* of the vertical line passing through the snap line origin.
|
||||
*/
|
||||
static bool pointHasEscapedSnapLineX( const VECTOR2I& aCursor, const VECTOR2I& aSnapLineOrigin,
|
||||
int aEscapeRange, EDA_ANGLE aLongRangeEscapeAngle )
|
||||
{
|
||||
if( std::abs( aCursor.x - aSnapLineOrigin.x ) < aEscapeRange )
|
||||
{
|
||||
return false;
|
||||
}
|
||||
EDA_ANGLE angle = EDA_ANGLE( aCursor - aSnapLineOrigin ) + EDA_ANGLE( 90, DEGREES_T );
|
||||
return std::abs( angle.Normalize90() ) > aLongRangeEscapeAngle;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* As above, but for the Y direction.
|
||||
*/
|
||||
static bool pointHasEscapedSnapLineY( const VECTOR2I& aCursor, const VECTOR2I& aSnapLineOrigin,
|
||||
int aEscapeRange, EDA_ANGLE aLongRangeEscapeAngle )
|
||||
{
|
||||
if( std::abs( aCursor.y - aSnapLineOrigin.y ) < aEscapeRange )
|
||||
{
|
||||
return false;
|
||||
}
|
||||
EDA_ANGLE angle = EDA_ANGLE( aCursor - aSnapLineOrigin );
|
||||
return std::abs( angle.Normalize90() ) > aLongRangeEscapeAngle;
|
||||
}
|
||||
|
||||
|
||||
OPT_VECTOR2I SNAP_LINE_MANAGER::GetNearestSnapLinePoint( const VECTOR2I& aCursor,
|
||||
const VECTOR2I& aNearestGrid,
|
||||
std::optional<int> aDistToNearest,
|
||||
int aSnapRange ) const
|
||||
{
|
||||
// return std::nullopt;
|
||||
if( m_snapLineOrigin )
|
||||
wxUnusedVar( aNearestGrid );
|
||||
|
||||
if( !m_snapLineOrigin || m_directions.empty() )
|
||||
return std::nullopt;
|
||||
|
||||
const bool gridBetterThanNearest = !aDistToNearest || *aDistToNearest > aSnapRange;
|
||||
|
||||
if( !gridBetterThanNearest )
|
||||
return std::nullopt;
|
||||
|
||||
const int escapeRange = 2 * aSnapRange;
|
||||
const EDA_ANGLE longRangeEscapeAngle( 4, DEGREES_T );
|
||||
|
||||
const VECTOR2D origin( *m_snapLineOrigin );
|
||||
const VECTOR2D cursor( aCursor );
|
||||
const VECTOR2D delta = cursor - origin;
|
||||
|
||||
double bestPerpDistance = std::numeric_limits<double>::max();
|
||||
std::optional<VECTOR2I> bestSnapPoint;
|
||||
|
||||
for( const VECTOR2I& direction : m_directions )
|
||||
{
|
||||
bool snapLine = false;
|
||||
VECTOR2I bestSnapPoint = aNearestGrid;
|
||||
VECTOR2D dirVector( direction );
|
||||
double dirLength = dirVector.EuclideanNorm();
|
||||
|
||||
// If there's no snap anchor, or it's too far away, prefer the grid
|
||||
const bool gridBetterThanNearest = !aDistToNearest || *aDistToNearest > aSnapRange;
|
||||
if( dirLength == 0.0 )
|
||||
continue;
|
||||
|
||||
// The escape range is how far you go before the snap line is de-activated.
|
||||
// Make this a bit more forgiving than the snap range, as you can easily cancel
|
||||
// deliberately with a mouse move.
|
||||
// These are both a bit arbitrary, and can be adjusted as preferred
|
||||
const int escapeRange = 2 * aSnapRange;
|
||||
const EDA_ANGLE longRangeEscapeAngle( 4, DEGREES_T );
|
||||
VECTOR2D dirUnit = dirVector / dirLength;
|
||||
|
||||
const bool escapedX = pointHasEscapedSnapLineX( aCursor, *m_snapLineOrigin, escapeRange,
|
||||
longRangeEscapeAngle );
|
||||
const bool escapedY = pointHasEscapedSnapLineY( aCursor, *m_snapLineOrigin, escapeRange,
|
||||
longRangeEscapeAngle );
|
||||
double distanceAlong = delta.Dot( dirUnit );
|
||||
VECTOR2D projection = origin + dirUnit * distanceAlong;
|
||||
VECTOR2D offset = delta - dirUnit * distanceAlong;
|
||||
double perpDistance = offset.EuclideanNorm();
|
||||
|
||||
/// Allows de-snapping from the line if you are closer to another snap point
|
||||
/// Or if you have moved far enough away from the line
|
||||
if( !escapedX && gridBetterThanNearest )
|
||||
if( perpDistance > aSnapRange )
|
||||
continue;
|
||||
|
||||
bool escaped = false;
|
||||
|
||||
if( perpDistance >= escapeRange )
|
||||
{
|
||||
bestSnapPoint.x = m_snapLineOrigin->x;
|
||||
snapLine = true;
|
||||
EDA_ANGLE deltaAngle( delta );
|
||||
EDA_ANGLE directionAngle( dirVector );
|
||||
double angleDiff = ( deltaAngle - directionAngle ).Normalize180().AsDegrees();
|
||||
|
||||
if( std::abs( angleDiff ) > longRangeEscapeAngle.AsDegrees() )
|
||||
escaped = true;
|
||||
}
|
||||
|
||||
if( !escapedY && gridBetterThanNearest )
|
||||
if( !escaped && perpDistance < bestPerpDistance )
|
||||
{
|
||||
bestSnapPoint.y = m_snapLineOrigin->y;
|
||||
snapLine = true;
|
||||
}
|
||||
|
||||
if( snapLine )
|
||||
{
|
||||
return bestSnapPoint;
|
||||
bestPerpDistance = perpDistance;
|
||||
bestSnapPoint = VECTOR2I( KiROUND( projection.x ), KiROUND( projection.y ) );
|
||||
}
|
||||
}
|
||||
|
||||
if( bestSnapPoint )
|
||||
return *bestSnapPoint;
|
||||
|
||||
return std::nullopt;
|
||||
}
|
||||
|
||||
|
||||
void SNAP_LINE_MANAGER::notifyGuideChange()
|
||||
{
|
||||
if( m_snapManager )
|
||||
m_snapManager->UpdateSnapGuides();
|
||||
}
|
||||
|
||||
|
||||
SNAP_MANAGER::SNAP_MANAGER( KIGFX::CONSTRUCTION_GEOM& aHelper ) :
|
||||
CONSTRUCTION_VIEW_HANDLER( aHelper ), m_snapLineManager( *this ),
|
||||
m_constructionManager( *this )
|
||||
m_constructionManager( *this ), m_snapGuideColor( KIGFX::COLOR4D::WHITE ),
|
||||
m_snapGuideHighlightColor( KIGFX::COLOR4D::WHITE )
|
||||
{
|
||||
}
|
||||
|
||||
@@ -540,13 +641,67 @@ void SNAP_MANAGER::updateView()
|
||||
if( m_updateCallback )
|
||||
{
|
||||
bool showAnything = m_constructionManager.HasActiveConstruction()
|
||||
|| m_snapLineManager.HasCompleteSnapLine();
|
||||
|| m_snapLineManager.HasCompleteSnapLine()
|
||||
|| ( m_snapLineManager.GetSnapLineOrigin()
|
||||
&& !m_snapLineManager.GetDirections().empty() );
|
||||
|
||||
m_updateCallback( showAnything );
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
void SNAP_MANAGER::SetSnapGuideColors( const KIGFX::COLOR4D& aBase, const KIGFX::COLOR4D& aHighlight )
|
||||
{
|
||||
m_snapGuideColor = aBase;
|
||||
m_snapGuideHighlightColor = aHighlight;
|
||||
UpdateSnapGuides();
|
||||
}
|
||||
|
||||
|
||||
void SNAP_MANAGER::UpdateSnapGuides()
|
||||
{
|
||||
std::vector<KIGFX::CONSTRUCTION_GEOM::SNAP_GUIDE> guides;
|
||||
|
||||
const OPT_VECTOR2I& origin = m_snapLineManager.GetSnapLineOrigin();
|
||||
const std::vector<VECTOR2I>& directions = m_snapLineManager.GetDirections();
|
||||
|
||||
if( origin && !directions.empty() )
|
||||
{
|
||||
const std::optional<int> activeDirection = m_snapLineManager.GetActiveDirection();
|
||||
const int guideLength = 500000;
|
||||
|
||||
for( size_t ii = 0; ii < directions.size(); ++ii )
|
||||
{
|
||||
const VECTOR2I& direction = directions[ii];
|
||||
|
||||
if( direction.x == 0 && direction.y == 0 )
|
||||
continue;
|
||||
|
||||
VECTOR2I scaled = direction * guideLength;
|
||||
|
||||
KIGFX::CONSTRUCTION_GEOM::SNAP_GUIDE guide;
|
||||
guide.Segment = SEG( *origin - scaled, *origin + scaled );
|
||||
|
||||
if( activeDirection && *activeDirection == static_cast<int>( ii ) )
|
||||
{
|
||||
guide.LineWidth = 2;
|
||||
guide.Color = m_snapGuideHighlightColor;
|
||||
}
|
||||
else
|
||||
{
|
||||
guide.LineWidth = 1;
|
||||
guide.Color = m_snapGuideColor;
|
||||
}
|
||||
|
||||
guides.push_back( guide );
|
||||
}
|
||||
}
|
||||
|
||||
GetViewItem().SetSnapGuides( std::move( guides ) );
|
||||
updateView();
|
||||
}
|
||||
|
||||
|
||||
std::vector<CONSTRUCTION_MANAGER::CONSTRUCTION_ITEM_BATCH>
|
||||
SNAP_MANAGER::GetConstructionItems() const
|
||||
{
|
||||
@@ -566,13 +721,24 @@ SNAP_MANAGER::GetConstructionItems() const
|
||||
{},
|
||||
} );
|
||||
|
||||
// One horizontal and one vertical infinite line from the snap point
|
||||
snapPointItem.Constructions.push_back(
|
||||
LINE{ *snapLineOrigin, *snapLineOrigin + VECTOR2I( 100000, 0 ) } );
|
||||
snapPointItem.Constructions.push_back(
|
||||
LINE{ *snapLineOrigin, *snapLineOrigin + VECTOR2I( 0, 100000 ) } );
|
||||
const std::vector<VECTOR2I>& directions = m_snapLineManager.GetDirections();
|
||||
const std::optional<int> activeDirection = m_snapLineManager.GetActiveDirection();
|
||||
|
||||
batches.push_back( std::move( batch ) );
|
||||
for( size_t ii = 0; ii < directions.size(); ++ii )
|
||||
{
|
||||
const VECTOR2I& direction = directions[ii];
|
||||
|
||||
VECTOR2I scaledDirection = direction * 100000;
|
||||
|
||||
CONSTRUCTION_MANAGER::CONSTRUCTION_ITEM::DRAWABLE_ENTRY entry;
|
||||
entry.Drawable = LINE{ *snapLineOrigin, *snapLineOrigin + scaledDirection };
|
||||
entry.LineWidth = ( activeDirection && *activeDirection == static_cast<int>( ii ) ) ? 2 : 1;
|
||||
|
||||
snapPointItem.Constructions.push_back( entry );
|
||||
}
|
||||
|
||||
if( !snapPointItem.Constructions.empty() )
|
||||
batches.push_back( std::move( batch ) );
|
||||
}
|
||||
|
||||
return batches;
|
||||
|
||||
+117
-8
@@ -24,13 +24,13 @@
|
||||
#include "tool/grid_helper.h"
|
||||
|
||||
#include <functional>
|
||||
#include <cmath>
|
||||
#include <limits>
|
||||
|
||||
#include <advanced_config.h>
|
||||
#include <gal/graphics_abstraction_layer.h>
|
||||
#include <gal/painter.h>
|
||||
#include <math/util.h> // for KiROUND
|
||||
#include <math/vector2d.h>
|
||||
#include <render_settings.h>
|
||||
#include <tool/tool_manager.h>
|
||||
#include <tool/tools_holder.h>
|
||||
#include <view/view.h>
|
||||
@@ -61,12 +61,8 @@ GRID_HELPER::GRID_HELPER( TOOL_MANAGER* aToolMgr, int aConstructionLayer ) :
|
||||
if( !m_toolMgr )
|
||||
return;
|
||||
|
||||
KIGFX::VIEW* view = m_toolMgr->GetView();
|
||||
KIGFX::RENDER_SETTINGS* settings = view->GetPainter()->GetSettings();
|
||||
|
||||
const KIGFX::COLOR4D constructionColour = settings->GetLayerColor( aConstructionLayer );
|
||||
m_constructionGeomPreview.SetPersistentColor( constructionColour );
|
||||
m_constructionGeomPreview.SetColor( constructionColour.WithAlpha( 0.7 ) );
|
||||
KIGFX::VIEW* view = m_toolMgr->GetView();
|
||||
wxUnusedVar( aConstructionLayer );
|
||||
|
||||
view->Add( &m_constructionGeomPreview );
|
||||
view->SetVisible( &m_constructionGeomPreview, false );
|
||||
@@ -135,6 +131,119 @@ void GRID_HELPER::showConstructionGeometry( bool aShow )
|
||||
}
|
||||
|
||||
|
||||
void GRID_HELPER::SetSnapLineDirections( const std::vector<VECTOR2I>& aDirections )
|
||||
{
|
||||
m_snapManager.GetSnapLineManager().SetDirections( aDirections );
|
||||
}
|
||||
|
||||
|
||||
void GRID_HELPER::SetSnapLineOrigin( const VECTOR2I& aOrigin )
|
||||
{
|
||||
m_snapManager.GetSnapLineManager().SetSnapLineOrigin( aOrigin );
|
||||
}
|
||||
|
||||
|
||||
void GRID_HELPER::ClearSnapLine()
|
||||
{
|
||||
m_snapManager.GetSnapLineManager().ClearSnapLine();
|
||||
}
|
||||
|
||||
|
||||
std::optional<VECTOR2I> GRID_HELPER::SnapToConstructionLines( const VECTOR2I& aPoint,
|
||||
const VECTOR2I& aNearestGrid,
|
||||
const VECTOR2D& aGrid,
|
||||
double aSnapRange ) const
|
||||
{
|
||||
const SNAP_LINE_MANAGER& snapLineManager = m_snapManager.GetSnapLineManager();
|
||||
const OPT_VECTOR2I& snapOrigin = snapLineManager.GetSnapLineOrigin();
|
||||
|
||||
if( !snapOrigin || snapLineManager.GetDirections().empty() )
|
||||
return std::nullopt;
|
||||
|
||||
const VECTOR2I& origin = *snapOrigin;
|
||||
|
||||
const std::vector<VECTOR2I>& directions = snapLineManager.GetDirections();
|
||||
const std::optional<int> activeDirection = snapLineManager.GetActiveDirection();
|
||||
|
||||
const VECTOR2D originVec( origin );
|
||||
const VECTOR2D cursorVec( aPoint );
|
||||
const VECTOR2D delta = cursorVec - originVec;
|
||||
|
||||
std::optional<VECTOR2I> bestPoint;
|
||||
double bestPerp = std::numeric_limits<double>::max();
|
||||
double bestDistance = std::numeric_limits<double>::max();
|
||||
|
||||
for( size_t ii = 0; ii < directions.size(); ++ii )
|
||||
{
|
||||
const VECTOR2I& dir = directions[ii];
|
||||
VECTOR2D dirVector( dir );
|
||||
double dirLength = dirVector.EuclideanNorm();
|
||||
|
||||
if( dirLength == 0.0 )
|
||||
continue;
|
||||
|
||||
VECTOR2D dirUnit = dirVector / dirLength;
|
||||
|
||||
double distanceAlong = delta.Dot( dirUnit );
|
||||
VECTOR2D projection = originVec + dirUnit * distanceAlong;
|
||||
VECTOR2D offset = delta - dirUnit * distanceAlong;
|
||||
double perpDistance = offset.EuclideanNorm();
|
||||
|
||||
double snapThreshold = aSnapRange;
|
||||
|
||||
if( activeDirection && *activeDirection == static_cast<int>( ii ) )
|
||||
snapThreshold *= 1.5;
|
||||
|
||||
if( perpDistance > snapThreshold )
|
||||
continue;
|
||||
|
||||
VECTOR2D candidate = projection;
|
||||
|
||||
if( canUseGrid() )
|
||||
{
|
||||
if( dir.x == 0 && dir.y != 0 )
|
||||
{
|
||||
candidate.x = origin.x;
|
||||
candidate.y = aNearestGrid.y;
|
||||
}
|
||||
else if( dir.y == 0 && dir.x != 0 )
|
||||
{
|
||||
candidate.x = aNearestGrid.x;
|
||||
candidate.y = origin.y;
|
||||
}
|
||||
else
|
||||
{
|
||||
double stepDistance = std::sqrt( aGrid.x * aGrid.x + aGrid.y * aGrid.y );
|
||||
|
||||
if( stepDistance == 0.0 )
|
||||
continue;
|
||||
|
||||
double steps = std::round( distanceAlong / stepDistance );
|
||||
candidate = originVec + dirUnit * ( steps * stepDistance );
|
||||
}
|
||||
}
|
||||
|
||||
VECTOR2I candidateInt( KiROUND( candidate.x ), KiROUND( candidate.y ) );
|
||||
|
||||
if( candidateInt == m_skipPoint )
|
||||
continue;
|
||||
|
||||
VECTOR2D candidateDelta( candidateInt.x - aPoint.x, candidateInt.y - aPoint.y );
|
||||
double candidateDistance = candidateDelta.EuclideanNorm();
|
||||
|
||||
if( perpDistance < bestPerp
|
||||
|| ( std::abs( perpDistance - bestPerp ) < 1e-9 && candidateDistance < bestDistance ) )
|
||||
{
|
||||
bestPerp = perpDistance;
|
||||
bestDistance = candidateDistance;
|
||||
bestPoint = candidateInt;
|
||||
}
|
||||
}
|
||||
|
||||
return bestPoint;
|
||||
}
|
||||
|
||||
|
||||
void GRID_HELPER::updateSnapPoint( const TYPED_POINT2I& aPoint )
|
||||
{
|
||||
if( !m_toolMgr )
|
||||
|
||||
@@ -156,10 +156,8 @@ VECTOR2I EE_GRID_HELPER::BestSnapAnchor( const VECTOR2I& aOrigin, GRID_HELPER_GR
|
||||
|
||||
VECTOR2I pt = aOrigin;
|
||||
VECTOR2I snapDist( snapRange, snapRange );
|
||||
bool snapLineX = false;
|
||||
bool snapLineY = false;
|
||||
bool snapPoint = false;
|
||||
bool gridChecked = false;
|
||||
bool snappedToAnchor = false;
|
||||
|
||||
BOX2I bb( VECTOR2I( aOrigin.x - snapRange / 2, aOrigin.y - snapRange / 2 ),
|
||||
VECTOR2I( snapRange, snapRange ) );
|
||||
@@ -185,42 +183,13 @@ VECTOR2I EE_GRID_HELPER::BestSnapAnchor( const VECTOR2I& aOrigin, GRID_HELPER_GR
|
||||
|
||||
showConstructionGeometry( m_enableSnap );
|
||||
|
||||
SNAP_LINE_MANAGER& snapLineManager = getSnapManager().GetSnapLineManager();
|
||||
std::optional<VECTOR2I> snapLineOrigin = snapLineManager.GetSnapLineOrigin();
|
||||
SNAP_LINE_MANAGER& snapLineManager = getSnapManager().GetSnapLineManager();
|
||||
const VECTOR2D gridSize = GetGridSize( aGrid );
|
||||
|
||||
if( m_enableSnapLine && m_snapItem && snapLineOrigin.has_value()
|
||||
&& m_skipPoint != *snapLineOrigin )
|
||||
{
|
||||
if( std::abs( snapLineOrigin->x - aOrigin.x ) < snapDist.x )
|
||||
{
|
||||
pt.x = snapLineOrigin->x;
|
||||
snapDist.x = std::abs( pt.x - aOrigin.x );
|
||||
snapLineX = true;
|
||||
}
|
||||
std::optional<VECTOR2I> guideSnap;
|
||||
|
||||
if( std::abs( snapLineOrigin->y - aOrigin.y ) < snapDist.y )
|
||||
{
|
||||
pt.y = snapLineOrigin->y;
|
||||
snapDist.y = std::abs( pt.y - aOrigin.y );
|
||||
snapLineY = true;
|
||||
}
|
||||
|
||||
if( canUseGrid() && std::abs( nearestGrid.x - aOrigin.x ) < snapDist.x )
|
||||
{
|
||||
pt.x = nearestGrid.x;
|
||||
snapDist.x = std::abs( nearestGrid.x - aOrigin.x );
|
||||
snapLineX = false;
|
||||
}
|
||||
|
||||
if( canUseGrid() && std::abs( nearestGrid.y - aOrigin.y ) < snapDist.y )
|
||||
{
|
||||
pt.y = nearestGrid.y;
|
||||
snapDist.y = std::abs( nearestGrid.y - aOrigin.y );
|
||||
snapLineY = false;
|
||||
}
|
||||
|
||||
gridChecked = true;
|
||||
}
|
||||
if( m_enableSnapLine )
|
||||
guideSnap = SnapToConstructionLines( aOrigin, nearestGrid, gridSize, snapRange );
|
||||
|
||||
if( m_enableSnap && nearest && nearest->Distance( aOrigin ) < snapDist.EuclideanNorm() )
|
||||
{
|
||||
@@ -230,29 +199,27 @@ VECTOR2I EE_GRID_HELPER::BestSnapAnchor( const VECTOR2I& aOrigin, GRID_HELPER_GR
|
||||
pt = nearestGrid;
|
||||
snapDist.x = std::abs( nearestGrid.x - aOrigin.x );
|
||||
snapDist.y = std::abs( nearestGrid.y - aOrigin.y );
|
||||
snapPoint = false;
|
||||
gridChecked = true;
|
||||
}
|
||||
else
|
||||
{
|
||||
pt = nearest->pos;
|
||||
snapDist.x = std::abs( nearest->pos.x - aOrigin.x );
|
||||
snapDist.y = std::abs( nearest->pos.y - aOrigin.y );
|
||||
snapPoint = true;
|
||||
snappedToAnchor = true;
|
||||
gridChecked = true;
|
||||
}
|
||||
|
||||
snapLineX = false;
|
||||
snapLineY = false;
|
||||
gridChecked = true;
|
||||
}
|
||||
|
||||
if( canUseGrid() && !gridChecked )
|
||||
pt = nearestGrid;
|
||||
|
||||
if( snapLineX || snapLineY )
|
||||
if( guideSnap && m_skipPoint != *guideSnap )
|
||||
{
|
||||
snapLineManager.SetSnapLineEnd( pt );
|
||||
snapLineManager.SetSnapLineEnd( *guideSnap );
|
||||
m_toolMgr->GetView()->SetVisible( &m_viewSnapPoint, false );
|
||||
m_snapItem = std::nullopt;
|
||||
return *guideSnap;
|
||||
}
|
||||
else if( snapPoint )
|
||||
|
||||
if( snappedToAnchor )
|
||||
{
|
||||
m_snapItem = *nearest;
|
||||
m_viewSnapPoint.SetPosition( pt );
|
||||
@@ -264,11 +231,15 @@ VECTOR2I EE_GRID_HELPER::BestSnapAnchor( const VECTOR2I& aOrigin, GRID_HELPER_GR
|
||||
else
|
||||
m_toolMgr->GetView()->SetVisible( &m_viewSnapPoint, true );
|
||||
}
|
||||
else
|
||||
{
|
||||
snapLineManager.ClearSnapLine();
|
||||
m_toolMgr->GetView()->SetVisible( &m_viewSnapPoint, false );
|
||||
}
|
||||
|
||||
if( !snappedToAnchor )
|
||||
m_snapItem = std::nullopt;
|
||||
|
||||
if( canUseGrid() && !gridChecked )
|
||||
pt = nearestGrid;
|
||||
|
||||
snapLineManager.SetSnapLineEnd( std::nullopt );
|
||||
m_toolMgr->GetView()->SetVisible( &m_viewSnapPoint, false );
|
||||
|
||||
return pt;
|
||||
}
|
||||
|
||||
@@ -854,6 +854,9 @@ public:
|
||||
{
|
||||
VECTOR2D gridScreenSize( m_gridSize );
|
||||
|
||||
gridScreenSize = VECTOR2D( std::max( 1.0, gridScreenSize.x ),
|
||||
std::max( 1.0, gridScreenSize.y ) );
|
||||
|
||||
double gridThreshold = computeMinGridSpacing() / m_worldScale;
|
||||
|
||||
if( m_gridStyle == GRID_STYLE::SMALL_CROSS )
|
||||
|
||||
@@ -46,6 +46,13 @@ public:
|
||||
// Supported items
|
||||
using DRAWABLE = std::variant<SEG, LINE, HALF_LINE, CIRCLE, SHAPE_ARC, VECTOR2I>;
|
||||
|
||||
struct SNAP_GUIDE
|
||||
{
|
||||
SEG Segment;
|
||||
COLOR4D Color;
|
||||
int LineWidth;
|
||||
};
|
||||
|
||||
CONSTRUCTION_GEOM();
|
||||
|
||||
wxString GetClass() const override { return wxT( "CONSTRUCTION_GEOM" ); }
|
||||
@@ -59,7 +66,8 @@ public:
|
||||
void SetColor( const COLOR4D& aColor ) { m_color = aColor; }
|
||||
void SetPersistentColor( const COLOR4D& aColor ) { m_persistentColor = aColor; }
|
||||
|
||||
void AddDrawable( const DRAWABLE& aItem, bool aIsPersistent );
|
||||
void AddDrawable( const DRAWABLE& aItem, bool aIsPersistent, int aLineWidth = 1 );
|
||||
void SetSnapGuides( std::vector<SNAP_GUIDE> aGuides );
|
||||
void ClearDrawables();
|
||||
|
||||
void SetSnapLine( const SEG& aLine ) { m_snapLine = aLine; }
|
||||
@@ -72,10 +80,12 @@ private:
|
||||
{
|
||||
DRAWABLE Item;
|
||||
bool IsPersistent;
|
||||
int LineWidth;
|
||||
};
|
||||
|
||||
// The items to draw
|
||||
std::vector<DRAWABLE_INFO> m_drawables;
|
||||
std::vector<SNAP_GUIDE> m_snapGuides;
|
||||
|
||||
// The snap line to draw
|
||||
std::optional<SEG> m_snapLine;
|
||||
|
||||
@@ -65,6 +65,9 @@ private:
|
||||
* This is a line that has a start point (the "snap origin") and an end point (the "snap end").
|
||||
* The end can only be set if the origin is set. If the origin is set, the end will be unset.
|
||||
*/
|
||||
class SNAP_MANAGER;
|
||||
|
||||
|
||||
class SNAP_LINE_MANAGER
|
||||
{
|
||||
public:
|
||||
@@ -120,14 +123,26 @@ public:
|
||||
OPT_VECTOR2I GetNearestSnapLinePoint( const VECTOR2I& aCursor, const VECTOR2I& aNearestGrid,
|
||||
std::optional<int> aDistToNearest, int snapRange ) const;
|
||||
|
||||
void SetDirections( const std::vector<VECTOR2I>& aDirections );
|
||||
|
||||
const std::vector<VECTOR2I>& GetDirections() const { return m_directions; }
|
||||
|
||||
std::optional<int> GetActiveDirection() const { return m_activeDirection; }
|
||||
|
||||
private:
|
||||
// If a snap point is "active", extra construction geometry is added to the helper
|
||||
// extending from the snap point to the cursor.
|
||||
OPT_VECTOR2I m_snapLineOrigin;
|
||||
OPT_VECTOR2I m_snapLineEnd;
|
||||
|
||||
std::vector<VECTOR2I> m_directions;
|
||||
std::optional<int> m_activeDirection;
|
||||
|
||||
// The view handler to update when the snap line changes
|
||||
CONSTRUCTION_VIEW_HANDLER& m_viewHandler;
|
||||
SNAP_MANAGER* m_snapManager;
|
||||
|
||||
void notifyGuideChange();
|
||||
};
|
||||
|
||||
|
||||
@@ -157,9 +172,16 @@ public:
|
||||
*/
|
||||
struct CONSTRUCTION_ITEM
|
||||
{
|
||||
SOURCE Source;
|
||||
EDA_ITEM* Item;
|
||||
std::vector<KIGFX::CONSTRUCTION_GEOM::DRAWABLE> Constructions;
|
||||
SOURCE Source;
|
||||
EDA_ITEM* Item;
|
||||
|
||||
struct DRAWABLE_ENTRY
|
||||
{
|
||||
KIGFX::CONSTRUCTION_GEOM::DRAWABLE Drawable;
|
||||
int LineWidth = 1;
|
||||
};
|
||||
|
||||
std::vector<DRAWABLE_ENTRY> Constructions;
|
||||
};
|
||||
|
||||
// A single batch of construction items. Once batch contains all the items (and associated
|
||||
@@ -253,6 +275,7 @@ public:
|
||||
void SetUpdateCallback( GFX_UPDATE_CALLBACK aCallback ) { m_updateCallback = aCallback; }
|
||||
|
||||
SNAP_LINE_MANAGER& GetSnapLineManager() { return m_snapLineManager; }
|
||||
const SNAP_LINE_MANAGER& GetSnapLineManager() const { return m_snapLineManager; }
|
||||
|
||||
CONSTRUCTION_MANAGER& GetConstructionManager() { return m_constructionManager; }
|
||||
|
||||
@@ -275,6 +298,9 @@ public:
|
||||
*/
|
||||
std::vector<CONSTRUCTION_MANAGER::CONSTRUCTION_ITEM_BATCH> GetConstructionItems() const;
|
||||
|
||||
void SetSnapGuideColors( const KIGFX::COLOR4D& aBase, const KIGFX::COLOR4D& aHighlight );
|
||||
void UpdateSnapGuides();
|
||||
|
||||
public:
|
||||
void updateView() override;
|
||||
|
||||
@@ -284,4 +310,6 @@ public:
|
||||
CONSTRUCTION_MANAGER m_constructionManager;
|
||||
|
||||
std::vector<VECTOR2I> m_referenceOnlyPoints;
|
||||
KIGFX::COLOR4D m_snapGuideColor;
|
||||
KIGFX::COLOR4D m_snapGuideHighlightColor;
|
||||
};
|
||||
|
||||
@@ -124,6 +124,13 @@ public:
|
||||
bool GetUseGrid() const { return m_enableGrid; }
|
||||
|
||||
void SetSnapLine( bool aSnap ) { m_enableSnapLine = aSnap; }
|
||||
void SetSnapLineDirections( const std::vector<VECTOR2I>& aDirections );
|
||||
void SetSnapLineOrigin( const VECTOR2I& aOrigin );
|
||||
void ClearSnapLine();
|
||||
std::optional<VECTOR2I> SnapToConstructionLines( const VECTOR2I& aPoint,
|
||||
const VECTOR2I& aNearestGrid,
|
||||
const VECTOR2D& aGrid,
|
||||
double aSnapRange ) const;
|
||||
|
||||
void SetMask( int aMask ) { m_maskTypes = aMask; }
|
||||
void SetMaskFlag( int aFlag ) { m_maskTypes |= aFlag; }
|
||||
|
||||
@@ -332,10 +332,16 @@ bool EDIT_TOOL::doMoveSelection( const TOOL_EVENT& aEvent, BOARD_COMMIT* aCommit
|
||||
controls->ForceCursorPosition( false );
|
||||
|
||||
auto displayConstraintsMessage =
|
||||
[editFrame]( bool constrained )
|
||||
[editFrame]( bool aHV45Enabled )
|
||||
{
|
||||
editFrame->DisplayConstraintsMsg( constrained ? _( "Constrain to H, V, 45" )
|
||||
: wxString( wxT( "" ) ) );
|
||||
wxString msg;
|
||||
|
||||
if( aHV45Enabled )
|
||||
msg = _( "Angle snap guides: H, V, 45°" );
|
||||
else
|
||||
msg.clear();
|
||||
|
||||
editFrame->DisplayConstraintsMsg( msg );
|
||||
};
|
||||
|
||||
auto updateStatusPopup =
|
||||
@@ -441,7 +447,7 @@ bool EDIT_TOOL::doMoveSelection( const TOOL_EVENT& aEvent, BOARD_COMMIT* aCommit
|
||||
VECTOR2I prevPos;
|
||||
bool enableLocalRatsnest = true;
|
||||
|
||||
bool hv45Mode = Is45Limited() && !evt->Modifier( MD_SHIFT );
|
||||
bool hv45Enabled = Is45Limited();
|
||||
bool eatFirstMouseUp = true;
|
||||
bool allowRedraw3D = cfg->m_Display.m_Live3DRefresh;
|
||||
bool showCourtyardConflicts = !m_isFootprintEditor && cfg->m_ShowCourtyardCollisions;
|
||||
@@ -456,7 +462,29 @@ bool EDIT_TOOL::doMoveSelection( const TOOL_EVENT& aEvent, BOARD_COMMIT* aCommit
|
||||
drc_on_move->Init( board );
|
||||
}
|
||||
|
||||
displayConstraintsMessage( hv45Mode );
|
||||
auto configureAngleSnap =
|
||||
[&]( bool aHV45Enabled )
|
||||
{
|
||||
std::vector<VECTOR2I> directions;
|
||||
|
||||
if( aHV45Enabled )
|
||||
{
|
||||
// H, V, and both 45° diagonals
|
||||
directions = { VECTOR2I( 1, 0 ), VECTOR2I( 0, 1 ),
|
||||
VECTOR2I( 1, 1 ), VECTOR2I( 1, -1 ) };
|
||||
}
|
||||
// Not enabled = no directions = no guides
|
||||
|
||||
grid.SetSnapLineDirections( directions );
|
||||
|
||||
if( !directions.empty() )
|
||||
grid.SetSnapLineOrigin( originalPos );
|
||||
else
|
||||
grid.ClearSnapLine();
|
||||
};
|
||||
|
||||
configureAngleSnap( hv45Enabled );
|
||||
displayConstraintsMessage( hv45Enabled );
|
||||
|
||||
// Prime the pump
|
||||
m_toolMgr->PostAction( ACTIONS::refreshPreview );
|
||||
@@ -506,12 +534,6 @@ bool EDIT_TOOL::doMoveSelection( const TOOL_EVENT& aEvent, BOARD_COMMIT* aCommit
|
||||
if( !selection.HasReferencePoint() )
|
||||
originalPos = m_cursor;
|
||||
|
||||
if( hv45Mode )
|
||||
{
|
||||
VECTOR2I moveVector = m_cursor - originalPos;
|
||||
m_cursor = originalPos + GetVectorSnapped45( moveVector );
|
||||
}
|
||||
|
||||
if( updateBBox )
|
||||
{
|
||||
originalBBox = BOX2I();
|
||||
@@ -611,12 +633,6 @@ bool EDIT_TOOL::doMoveSelection( const TOOL_EVENT& aEvent, BOARD_COMMIT* aCommit
|
||||
// start moving with the reference point attached to the cursor
|
||||
grid.SetAuxAxes( false );
|
||||
|
||||
if( hv45Mode )
|
||||
{
|
||||
VECTOR2I moveVector = m_cursor - originalPos;
|
||||
m_cursor = originalPos + GetVectorSnapped45( moveVector );
|
||||
}
|
||||
|
||||
movement = m_cursor - selection.GetReferencePoint();
|
||||
|
||||
// Drag items to the current cursor position
|
||||
@@ -665,6 +681,10 @@ bool EDIT_TOOL::doMoveSelection( const TOOL_EVENT& aEvent, BOARD_COMMIT* aCommit
|
||||
if( moveWithReference )
|
||||
{
|
||||
selection.SetReferencePoint( pickedReferencePoint );
|
||||
|
||||
if( hv45Enabled )
|
||||
grid.SetSnapLineOrigin( selection.GetReferencePoint() );
|
||||
|
||||
controls->ForceCursorPosition( true, pickedReferencePoint );
|
||||
m_cursor = pickedReferencePoint;
|
||||
}
|
||||
@@ -685,6 +705,10 @@ bool EDIT_TOOL::doMoveSelection( const TOOL_EVENT& aEvent, BOARD_COMMIT* aCommit
|
||||
}
|
||||
|
||||
selection.SetReferencePoint( snapped );
|
||||
|
||||
if( hv45Enabled )
|
||||
grid.SetSnapLineOrigin( selection.GetReferencePoint() );
|
||||
|
||||
grid.SetAuxAxes( true, snapped );
|
||||
|
||||
if( !editFrame->GetMoveWarpsCursor() )
|
||||
@@ -769,6 +793,8 @@ bool EDIT_TOOL::doMoveSelection( const TOOL_EVENT& aEvent, BOARD_COMMIT* aCommit
|
||||
originalPos = nextItem->GetPosition();
|
||||
m_selectionTool->AddItemToSel( nextItem );
|
||||
selection.SetReferencePoint( originalPos );
|
||||
if( hv45Enabled )
|
||||
grid.SetSnapLineOrigin( selection.GetReferencePoint() );
|
||||
|
||||
sel_items.clear();
|
||||
sel_items.push_back( nextItem );
|
||||
@@ -794,8 +820,9 @@ bool EDIT_TOOL::doMoveSelection( const TOOL_EVENT& aEvent, BOARD_COMMIT* aCommit
|
||||
}
|
||||
else if( evt->IsAction( &PCB_ACTIONS::toggleHV45Mode ) )
|
||||
{
|
||||
hv45Mode = Is45Limited();
|
||||
displayConstraintsMessage( hv45Mode );
|
||||
hv45Enabled = Is45Limited();
|
||||
configureAngleSnap( hv45Enabled );
|
||||
displayConstraintsMessage( hv45Enabled );
|
||||
evt->SetPassEvent( false );
|
||||
}
|
||||
else if( evt->IsAction( &ACTIONS::increment ) )
|
||||
|
||||
@@ -304,10 +304,20 @@ void PCB_GRID_HELPER::AddConstructionItems( std::vector<BOARD_ITEM*> aItems, boo
|
||||
// At this point, constructionDrawables can be empty, which is fine
|
||||
// (it means there's no additional construction geometry to draw, but
|
||||
// the item is still going to be proposed for activation)
|
||||
|
||||
// Convert the drawables to DRAWABLE_ENTRY format
|
||||
std::vector<CONSTRUCTION_MANAGER::CONSTRUCTION_ITEM::DRAWABLE_ENTRY> drawableEntries;
|
||||
drawableEntries.reserve( constructionDrawables.size() );
|
||||
for( auto& drawable : constructionDrawables )
|
||||
{
|
||||
drawableEntries.emplace_back(
|
||||
CONSTRUCTION_MANAGER::CONSTRUCTION_ITEM::DRAWABLE_ENTRY{ std::move( drawable ), 1 } );
|
||||
}
|
||||
|
||||
constructionItemsBatch->emplace_back( CONSTRUCTION_MANAGER::CONSTRUCTION_ITEM{
|
||||
CONSTRUCTION_MANAGER::SOURCE::FROM_ITEMS,
|
||||
item,
|
||||
std::move( constructionDrawables ),
|
||||
std::move( drawableEntries ),
|
||||
} );
|
||||
}
|
||||
|
||||
@@ -617,6 +627,15 @@ VECTOR2I PCB_GRID_HELPER::BestSnapAnchor( const VECTOR2I& aOrigin, const LSET& a
|
||||
OPT_VECTOR2I snapLineSnap = snapLineManager.GetNearestSnapLinePoint(
|
||||
aOrigin, nearestGrid, snapDist, snapRange );
|
||||
|
||||
if( !snapLineSnap )
|
||||
{
|
||||
std::optional<VECTOR2I> constructionSnap =
|
||||
SnapToConstructionLines( aOrigin, nearestGrid, GetGridSize( aGrid ), snapRange );
|
||||
|
||||
if( constructionSnap )
|
||||
snapLineSnap = *constructionSnap;
|
||||
}
|
||||
|
||||
// We found a better snap point that the nearest one
|
||||
if( snapLineSnap && m_skipPoint != *snapLineSnap )
|
||||
{
|
||||
@@ -719,14 +738,9 @@ VECTOR2I PCB_GRID_HELPER::BestSnapAnchor( const VECTOR2I& aOrigin, const LSET& a
|
||||
m_snapItem = std::nullopt;
|
||||
|
||||
if( !snapValid )
|
||||
{
|
||||
snapLineManager.ClearSnapLine();
|
||||
snapManager.GetConstructionManager().CancelProposal();
|
||||
}
|
||||
else
|
||||
{
|
||||
snapLineManager.SetSnapLineEnd( std::nullopt );
|
||||
}
|
||||
|
||||
snapLineManager.SetSnapLineEnd( std::nullopt );
|
||||
|
||||
m_toolMgr->GetView()->SetVisible( &m_viewSnapPoint, false );
|
||||
|
||||
@@ -980,7 +994,7 @@ void PCB_GRID_HELPER::computeAnchors( const std::vector<BOARD_ITEM*>& aItems,
|
||||
{
|
||||
BOARD_ITEM* involvedItem = static_cast<BOARD_ITEM*>( constructionItem.Item );
|
||||
|
||||
for( const KIGFX::CONSTRUCTION_GEOM::DRAWABLE& drawable : constructionItem.Constructions )
|
||||
for( const CONSTRUCTION_MANAGER::CONSTRUCTION_ITEM::DRAWABLE_ENTRY& drawable : constructionItem.Constructions )
|
||||
{
|
||||
std::visit(
|
||||
[&]( const auto& visited )
|
||||
@@ -1000,7 +1014,7 @@ void PCB_GRID_HELPER::computeAnchors( const std::vector<BOARD_ITEM*>& aItems,
|
||||
addAnchor( visited, SNAPPABLE | CONSTRUCTED, involvedItem, POINT_TYPE::PT_NONE );
|
||||
}
|
||||
},
|
||||
drawable );
|
||||
drawable.Drawable );
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user