KiCad PCB EDA Suite
polygon_geom_manager.cpp
Go to the documentation of this file.
1 /*
2  * This program source code file is part of KICAD, a free EDA CAD application.
3  *
4  * Copyright (C) 2017-2019 Kicad Developers, see AUTHORS.txt for contributors.
5  *
6  * This program is free software; you can redistribute it and/or
7  * modify it under the terms of the GNU General Public License
8  * as published by the Free Software Foundation; either version 2
9  * of the License, or (at your option) any later version.
10  *
11  * This program is distributed in the hope that it will be useful,
12  * but WITHOUT ANY WARRANTY; without even the implied warranty of
13  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14  * GNU General Public License for more details.
15  *
16  * You should have received a copy of the GNU General Public License
17  * along with this program; if not, you may find one here:
18  * http://www.gnu.org/licenses/old-licenses/gpl-2.0.html
19  * or you may search the http://www.gnu.org website for the version 2 license,
20  * or you may write to the Free Software Foundation, Inc.,
21  * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA
22  */
23 #include <limits>
24 
26 
28 
29 
31  m_client( aClient ),
32  m_leaderMode( LEADER_MODE::DIRECT ),
33  m_intersectionsAllowed( true )
34 {}
35 
36 
38 {
39  // if this is the first point, make sure the client is happy
40  // for us to continue
41  if( !IsPolygonInProgress() && !m_client.OnFirstPoint( *this ) )
42  return false;
43 
44  if( m_leaderPts.PointCount() > 1 )
45  {
46  // there are enough leader points - the next
47  // locked-in point is the end of the first leader
48  // segment
50  }
51  else
52  {
53  // no leader lines, directly add the cursor
54  m_lockedPoints.Append( aPt );
55  }
56 
57  // check for self-intersections
59  {
61  return false;
62  }
63 
64  m_client.OnGeometryChange( *this );
65  return true;
66 }
67 
68 
70 {
71 
72  m_client.OnComplete( *this );
73 }
74 
75 
77 {
78  m_leaderMode = aMode;
79 }
80 
81 
82 bool POLYGON_GEOM_MANAGER::IsSelfIntersecting( bool aIncludeLeaderPts ) const
83 {
84  auto pts( m_lockedPoints );
85 
86  if( aIncludeLeaderPts )
87  {
88  for( int i = 0; i < m_leaderPts.PointCount(); ++i )
89  if( m_leaderPts.CPoint( i ) != pts.CPoint( 0 ) )
90  pts.Append( m_leaderPts.CPoint( i ) );
91  }
92 
93  // line chain needs to be set as closed for proper checks
94  pts.SetClosed( true );
95 
96  return !!pts.SelfIntersecting();
97 }
98 
99 
101 {
102  updateLeaderPoints( aPos, aModifier );
103 }
104 
105 
107 {
108  return m_lockedPoints.PointCount() > 0;
109 }
110 
111 
113 {
114  return m_lockedPoints.PointCount() > 0 && m_lockedPoints.CPoint( 0 ) == aPt;
115 }
116 
117 
119 {
120  if( m_lockedPoints.PointCount() > 0 )
121  {
123  }
124 
125  // update the new last segment (was previously
126  // locked in), reusing last constraints
127  if( m_lockedPoints.PointCount() > 0 )
128  {
130  }
131 
132  m_client.OnGeometryChange( *this );
133 }
134 
135 
137 {
139  m_leaderPts.Clear();
140 
141  m_client.OnGeometryChange( *this );
142 }
143 
144 
146 {
147  wxCHECK( m_lockedPoints.PointCount() > 0, /*void*/ );
148  const VECTOR2I& lastPt = m_lockedPoints.CLastPoint();
149 
150  if( m_leaderMode == LEADER_MODE::DEG45 || aModifier == LEADER_MODE::DEG45 )
151  {
152  const VECTOR2I lineVector( aEndPoint - lastPt );
153  // get a restricted 45/H/V line from the last fixed point to the cursor
154  auto newEnd = lastPt + GetVectorSnapped45( lineVector );
155 
156  SEG first( lastPt, newEnd );
157  SEG test_seg = m_lockedPoints.CSegment( 0 );
158 
159  auto pt = first.IntersectLines( m_lockedPoints.CSegment( 0 ) );
160  int dist = pt ? ( aEndPoint - *pt ).EuclideanNorm() : std::numeric_limits<int>::max();
161 
162  for( int i = 1; i < 8; i++ )
163  {
164  test_seg.B = ( test_seg.B - test_seg.A ).Rotate( M_PI_4 ) + test_seg.A;
165  auto pt2 = first.IntersectLines( test_seg );
166  if( pt2 )
167  {
168  int dist2 = ( aEndPoint - *pt2 ).EuclideanNorm();
169  if( dist2 < dist )
170  {
171  dist = dist2;
172  pt = pt2;
173  }
174  }
175  }
176 
177  m_leaderPts = SHAPE_LINE_CHAIN( lastPt, newEnd );
178 
179  if( pt )
180  m_leaderPts.Append( *pt );
181  }
182  else
183  {
184  // direct segment
185  m_leaderPts = SHAPE_LINE_CHAIN( lastPt, aEndPoint );
186  }
187 
188  m_client.OnGeometryChange( *this );
189 }
double EuclideanNorm(const wxPoint &vector)
Euclidean norm of a 2D vector.
Definition: trigo.h:123
virtual void OnGeometryChange(const POLYGON_GEOM_MANAGER &aMgr)=0
Sent when the polygon geometry changes
void SetCursorPosition(const VECTOR2I &aPos, LEADER_MODE aModifier)
Set the current cursor position.
SHAPE_LINE_CHAIN m_lockedPoints
Point that have been "locked in"
static const int dist[10][10]
Definition: ar_matrix.cpp:320
LEADER_MODE
The kind of the leader line.
POLYGON_GEOM_MANAGER(CLIENT &aClient)
LEADER_MODE m_leaderMode
The current mode of the leader line
CLIENT & m_client
The "user" of the polygon data that is informed when the geometry changes
OPT_VECTOR2I IntersectLines(const SEG &aSeg) const
Function IntersectLines()
Definition: seg.h:183
bool NewPointClosesOutline(const VECTOR2I &aPt) const
int PointCount() const
Function PointCount()
void SetLeaderMode(LEADER_MODE aMode)
Set the leader mode to use when calculating the leader/returner lines.
void Append(int aX, int aY, bool aAllowDuplication=false)
Function Append()
const VECTOR2I & CPoint(int aIndex) const
Function CPoint()
Unconstrained point-to-point
"Listener" interface for a class that wants to be updated about polygon geometry changes
virtual bool OnFirstPoint(POLYGON_GEOM_MANAGER &aMgr)=0
Called before the first point is added - clients can do initialisation here, and can veto the start o...
bool IsSelfIntersecting(bool aIncludeLeaderPts) const
Checks whether the locked points constitute a self-intersecting outline.
a few functions useful in geometry calculations.
void Remove(int aStartIndex, int aEndIndex)
Function Remove()
void DeleteLastCorner()
Remove the last-added point from the polygon.
Definition: seg.h:36
bool m_intersectionsAllowed
Flag enabling self-intersecting polygons
const SEG CSegment(int aIndex) const
Function CSegment()
#define max(a, b)
Definition: auxiliary.h:86
Class SHAPE_LINE_CHAIN.
size_t i
Definition: json11.cpp:597
VECTOR2I A
Definition: seg.h:44
void Reset()
Clear the manager state and start again.
const VECTOR2I & CLastPoint() const
Returns the last point in the line chain.
void Clear()
Function Clear() Removes all points from the line chain.
VECTOR2< T > GetVectorSnapped45(const VECTOR2< T > &aVec)
Snap a vector onto the nearest 0, 45 or 90 degree line.
virtual void OnComplete(const POLYGON_GEOM_MANAGER &aMgr)=0
Called when the polygon is complete
void updateLeaderPoints(const VECTOR2I &aEndPoint, LEADER_MODE aModifier=LEADER_MODE::DIRECT)
Update the leader line points based on a new endpoint (probably a cursor position)
bool AddPoint(const VECTOR2I &aPt)
Lock in a polygon point.
void SetFinished()
Mark the polygon finished and update the client.
SHAPE_LINE_CHAIN m_leaderPts
Points in the temporary "leader" line(s)
VECTOR2I B
Definition: seg.h:45