KiCad PCB EDA Suite
lib_bezier.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) 2004-2020 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 
24 #include <fctsys.h>
25 #include <gr_basic.h>
26 #include <macros.h>
27 #include <sch_draw_panel.h>
28 #include <plotter.h>
29 #include <trigo.h>
30 #include <bezier_curves.h>
31 #include <base_units.h>
32 #include <eda_draw_frame.h>
33 #include <msgpanel.h>
34 #include <eda_draw_frame.h>
35 #include <general.h>
36 #include <lib_bezier.h>
37 #include <transform.h>
39 
40 
42  LIB_ITEM( LIB_BEZIER_T, aParent )
43 {
44  m_Fill = NO_FILL;
45  m_Width = 0;
46  m_isFillable = true;
47 }
48 
49 
51 {
52  return new LIB_BEZIER( *this );
53 }
54 
55 
56 int LIB_BEZIER::compare( const LIB_ITEM& aOther, LIB_ITEM::COMPARE_FLAGS aCompareFlags ) const
57 {
58  wxASSERT( aOther.Type() == LIB_BEZIER_T );
59 
60  int retv = LIB_ITEM::compare( aOther );
61 
62  if( retv )
63  return retv;
64 
65  const LIB_BEZIER* tmp = ( LIB_BEZIER* ) &aOther;
66 
67  if( m_BezierPoints.size() != tmp->m_BezierPoints.size() )
68  return m_BezierPoints.size() - tmp->m_BezierPoints.size();
69 
70  for( size_t i = 0; i < m_BezierPoints.size(); i++ )
71  {
72  if( m_BezierPoints[i].x != tmp->m_BezierPoints[i].x )
73  return m_BezierPoints[i].x - tmp->m_BezierPoints[i].x;
74 
75  if( m_BezierPoints[i].y != tmp->m_BezierPoints[i].y )
76  return m_BezierPoints[i].y - tmp->m_BezierPoints[i].y;
77  }
78 
79  return 0;
80 }
81 
82 
83 void LIB_BEZIER::Offset( const wxPoint& aOffset )
84 {
85  size_t i;
86 
87  for( i = 0; i < m_BezierPoints.size(); i++ )
88  m_BezierPoints[i] += aOffset;
89 
90  for( i = 0; i < m_PolyPoints.size(); i++ )
91  m_PolyPoints[i] += aOffset;
92 }
93 
94 
95 void LIB_BEZIER::MoveTo( const wxPoint& aPosition )
96 {
97  if ( !m_PolyPoints.size() )
98  m_PolyPoints.emplace_back(0, 0 );
99 
100  Offset( aPosition - m_PolyPoints[ 0 ] );
101 }
102 
104 {
105  if ( !m_PolyPoints.size() )
106  return wxPoint(0, 0);
107 
108  return m_PolyPoints[0];
109 }
110 
111 void LIB_BEZIER::MirrorHorizontal( const wxPoint& aCenter )
112 {
113  size_t i, imax = m_PolyPoints.size();
114 
115  for( i = 0; i < imax; i++ )
116  {
117  m_PolyPoints[i].x -= aCenter.x;
118  m_PolyPoints[i].x *= -1;
119  m_PolyPoints[i].x += aCenter.x;
120  }
121 
122  imax = m_BezierPoints.size();
123 
124  for( i = 0; i < imax; i++ )
125  {
126  m_BezierPoints[i].x -= aCenter.x;
127  m_BezierPoints[i].x *= -1;
128  m_BezierPoints[i].x += aCenter.x;
129  }
130 }
131 
132 void LIB_BEZIER::MirrorVertical( const wxPoint& aCenter )
133 {
134  size_t i, imax = m_PolyPoints.size();
135 
136  for( i = 0; i < imax; i++ )
137  {
138  m_PolyPoints[i].y -= aCenter.y;
139  m_PolyPoints[i].y *= -1;
140  m_PolyPoints[i].y += aCenter.y;
141  }
142 
143  imax = m_BezierPoints.size();
144 
145  for( i = 0; i < imax; i++ )
146  {
147  m_BezierPoints[i].y -= aCenter.y;
148  m_BezierPoints[i].y *= -1;
149  m_BezierPoints[i].y += aCenter.y;
150  }
151 }
152 
153 void LIB_BEZIER::Rotate( const wxPoint& aCenter, bool aRotateCCW )
154 {
155  int rot_angle = aRotateCCW ? -900 : 900;
156 
157  for( wxPoint& point : m_PolyPoints )
158  RotatePoint( &point, aCenter, rot_angle );
159 
160  for( wxPoint& bezierPoint : m_BezierPoints )
161  RotatePoint( &bezierPoint, aCenter, rot_angle );
162 }
163 
164 
165 void LIB_BEZIER::Plot( PLOTTER* aPlotter, const wxPoint& aOffset, bool aFill,
166  const TRANSFORM& aTransform )
167 {
168  wxASSERT( aPlotter != NULL );
169 
170  static std::vector< wxPoint > cornerList;
171  cornerList.clear();
172 
173  for( wxPoint pos : m_PolyPoints )
174  {
175  pos = aTransform.TransformCoordinate( pos ) + aOffset;
176  cornerList.push_back( pos );
177  }
178 
179  if( aFill && m_Fill == FILLED_WITH_BG_BODYCOLOR )
180  {
181  aPlotter->SetColor( aPlotter->RenderSettings()->GetLayerColor( LAYER_DEVICE_BACKGROUND ) );
182  aPlotter->PlotPoly( cornerList, FILLED_WITH_BG_BODYCOLOR, 0 );
183  }
184 
185  bool already_filled = m_Fill == FILLED_WITH_BG_BODYCOLOR;
186  int pen_size = GetPenWidth();
187 
188  if( !already_filled || pen_size > 0 )
189  {
190  pen_size = std::max( pen_size, aPlotter->RenderSettings()->GetDefaultPenWidth() );
191 
192  aPlotter->SetColor( aPlotter->RenderSettings()->GetLayerColor( LAYER_DEVICE ) );
193  aPlotter->PlotPoly( cornerList, already_filled ? NO_FILL : m_Fill, pen_size );
194  }
195 }
196 
197 
199 {
200  // Historically 0 meant "default width" and negative numbers meant "don't stroke".
201  if( m_Width < 0 && GetFillMode() != NO_FILL )
202  return 0;
203  else
204  return std::max( m_Width, 1 );
205 }
206 
207 
208 void LIB_BEZIER::print( RENDER_SETTINGS* aSettings, const wxPoint& aOffset, void* aData,
209  const TRANSFORM& aTransform )
210 {
211  bool forceNoFill = static_cast<bool>( aData );
212  int penWidth = GetPenWidth();
213 
214  if( forceNoFill && m_Fill != NO_FILL && penWidth == 0 )
215  return;
216 
217  std::vector<wxPoint> PolyPointsTraslated;
218 
219  wxDC* DC = aSettings->GetPrintDC();
220  COLOR4D color = aSettings->GetLayerColor( LAYER_DEVICE );
221  BEZIER_POLY converter( m_BezierPoints );
222  converter.GetPoly( m_PolyPoints );
223 
224  PolyPointsTraslated.clear();
225 
226  for( wxPoint& point : m_PolyPoints )
227  PolyPointsTraslated.push_back( aTransform.TransformCoordinate( point ) + aOffset );
228 
229  if( forceNoFill || m_Fill == NO_FILL )
230  {
231  penWidth = std::max( penWidth, aSettings->GetDefaultPenWidth() );
232 
233  GRPoly( nullptr, DC, m_PolyPoints.size(), &PolyPointsTraslated[0], false, penWidth,
234  color, color );
235  }
236  else
237  {
240 
241  GRPoly( nullptr, DC, m_PolyPoints.size(), &PolyPointsTraslated[0], true, penWidth,
242  color, color );
243  }
244 }
245 
246 
247 bool LIB_BEZIER::HitTest( const wxPoint& aRefPos, int aAccuracy ) const
248 {
249  int mindist = std::max( aAccuracy + GetPenWidth() / 2,
250  Mils2iu( MINIMUM_SELECTION_DISTANCE ) );
251  wxPoint start, end;
252 
253  for( unsigned ii = 1; ii < GetCornerCount(); ii++ )
254  {
257 
258  if ( TestSegmentHit( aRefPos, start, end, mindist ) )
259  return true;
260  }
261 
262  return false;
263 }
264 
265 
266 bool LIB_BEZIER::HitTest( const EDA_RECT& aRect, bool aContained, int aAccuracy ) const
267 {
268  if( m_Flags & ( STRUCT_DELETED | SKIP_STRUCT ) )
269  return false;
270 
271  EDA_RECT sel = aRect;
272 
273  if ( aAccuracy )
274  sel.Inflate( aAccuracy );
275 
276  if( aContained )
277  return sel.Contains( GetBoundingBox() );
278 
279  // Fast test: if aRect is outside the polygon bounding box, rectangles cannot intersect
280  if( !sel.Intersects( GetBoundingBox() ) )
281  return false;
282 
283  // Account for the width of the line
284  sel.Inflate( GetWidth() / 2 );
285  unsigned count = m_BezierPoints.size();
286 
287  for( unsigned ii = 1; ii < count; ii++ )
288  {
291 
292  // Test if the point is within aRect
293  if( sel.Contains( vertex ) )
294  return true;
295 
296  // Test if this edge intersects aRect
297  if( sel.Intersects( vertex, vertexNext ) )
298  return true;
299  }
300 
301  return false;
302 }
303 
304 
306 {
307  EDA_RECT rect;
308  int xmin, xmax, ymin, ymax;
309 
310  if( !GetCornerCount() )
311  return rect;
312 
313  xmin = xmax = m_PolyPoints[0].x;
314  ymin = ymax = m_PolyPoints[0].y;
315 
316  for( unsigned ii = 1; ii < GetCornerCount(); ii++ )
317  {
318  xmin = std::min( xmin, m_PolyPoints[ii].x );
319  xmax = std::max( xmax, m_PolyPoints[ii].x );
320  ymin = std::min( ymin, m_PolyPoints[ii].y );
321  ymax = std::max( ymax, m_PolyPoints[ii].y );
322  }
323 
324  rect.SetOrigin( xmin, ymin );
325  rect.SetEnd( xmax, ymax );
326  rect.Inflate( ( GetPenWidth() / 2 ) + 1 );
327 
328  rect.RevertYAxis();
329 
330  return rect;
331 }
332 
333 
334 void LIB_BEZIER::GetMsgPanelInfo( EDA_DRAW_FRAME* aFrame, std::vector<MSG_PANEL_ITEM>& aList )
335 {
336  wxString msg;
337  EDA_RECT bBox = GetBoundingBox();
338 
339  LIB_ITEM::GetMsgPanelInfo( aFrame, aList );
340 
341  msg = MessageTextFromValue( aFrame->GetUserUnits(), m_Width, true );
342 
343  aList.emplace_back( _( "Line Width" ), msg, BLUE );
344 
345  msg.Printf( wxT( "(%d, %d, %d, %d)" ),
346  bBox.GetOrigin().x,
347  bBox.GetOrigin().y,
348  bBox.GetEnd().x,
349  bBox.GetEnd().y );
350 
351  aList.emplace_back( _( "Bounding Box" ), msg, BROWN );
352 }
353 
355 {
356  if( !m_PolyPoints.size() )
357  return wxPoint(0, 0);
358 
359  return m_PolyPoints[0];
360 }
void MoveTo(const wxPoint &aPosition) override
Move a draw object to aPosition.
Definition: lib_bezier.cpp:95
const wxPoint GetOffset() const
Definition: lib_bezier.cpp:103
RENDER_SETTINGS Contains all the knowledge about how graphical objects are drawn on any output surfac...
Implementation of conversion functions that require both schematic and board internal units.
virtual void SetColor(COLOR4D color)=0
LIB_BEZIER(LIB_PART *aParent)
Definition: lib_bezier.cpp:41
std::vector< wxPoint > m_BezierPoints
Definition: lib_bezier.h:37
void GetPoly(std::vector< wxPoint > &aOutput, int aMinSegLen=0)
Converts Bezier curve to a polygon.
void GRPoly(EDA_RECT *ClipBox, wxDC *DC, int n, const wxPoint *Points, bool Fill, int width, COLOR4D Color, COLOR4D BgColor)
Definition: gr_basic.cpp:544
#define SKIP_STRUCT
flag indicating that the structure should be ignored
Definition: base_struct.h:128
int color
Definition: DXF_plotter.cpp:61
const EDA_RECT GetBoundingBox() const override
Function GetBoundingBox returns the orthogonal, bounding box of this object for display purposes.
Definition: lib_bezier.cpp:305
bool HitTest(const wxPoint &aPosition, int aAccuracy=0) const override
Function HitTest tests if aPosition is contained within or on the bounding box of an item.
Definition: lib_bezier.cpp:247
void Plot(PLOTTER *aPlotter, const wxPoint &aOffset, bool aFill, const TRANSFORM &aTransform) override
Plot the draw item using the plot object.
Definition: lib_bezier.cpp:165
FILL_T GetFillMode() const
Definition: lib_item.h:301
Definition: color4d.h:61
const COLOR4D & GetLayerColor(int aLayer) const
Function GetLayerColor Returns the color used to draw a layer.
TRANSFORM DefaultTransform
void SetOrigin(const wxPoint &pos)
Definition: eda_rect.h:131
void RotatePoint(int *pX, int *pY, double angle)
Definition: trigo.cpp:208
virtual void PlotPoly(const std::vector< wxPoint > &aCornerList, FILL_T aFill, int aWidth=USE_DEFAULT_LINE_WIDTH, void *aData=NULL)=0
Function PlotPoly.
The base class for create windows for drawing purpose.
void GetMsgPanelInfo(EDA_DRAW_FRAME *aFrame, std::vector< MSG_PANEL_ITEM > &aList) override
Function GetMsgPanelInfo populates aList of MSG_PANEL_ITEM objects with it's internal state for displ...
Definition: lib_bezier.cpp:334
void RevertYAxis()
Function RevertYAxis Mirror the rectangle from the X axis (negate Y pos and size)
Definition: eda_rect.h:209
wxPoint GetPosition() const override
Definition: lib_bezier.cpp:354
bool Contains(const wxPoint &aPoint) const
Function Contains.
wxPoint TransformCoordinate(const wxPoint &aPoint) const
Calculate a new coordinate according to the mirror/rotation transform.
Definition: transform.cpp:42
The base class for drawable items used by schematic library components.
Definition: lib_item.h:61
This file contains miscellaneous commonly used macros and functions.
bool TestSegmentHit(const wxPoint &aRefPoint, wxPoint aStart, wxPoint aEnd, int aDist)
Test if aRefPoint is with aDistance on the line defined by aStart and aEnd.
Definition: trigo.cpp:129
int GetWidth() const override
Definition: lib_bezier.h:86
unsigned GetCornerCount() const
Definition: lib_bezier.h:66
const wxPoint GetEnd() const
Definition: eda_rect.h:116
void Offset(const wxPoint &aOffset) override
Set the drawing object by aOffset from the current position.
Definition: lib_bezier.cpp:83
void MirrorHorizontal(const wxPoint &aCenter) override
Mirror the draw object along the horizontal (X) axis about aCenter point.
Definition: lib_bezier.cpp:111
for transforming drawing coordinates for a wxDC device context.
Definition: transform.h:45
void Rotate(const wxPoint &aCenter, bool aRotateCCW=true) override
Rotate the object about aCenter point.
Definition: lib_bezier.cpp:153
void print(RENDER_SETTINGS *aSettings, const wxPoint &aOffset, void *aData, const TRANSFORM &aTransform) override
Print the item to aDC.
Definition: lib_bezier.cpp:208
#define NULL
COMPARE_FLAGS
The list of flags used by the compare function.
Definition: lib_item.h:116
const wxPoint GetOrigin() const
Definition: eda_rect.h:114
void SetEnd(int x, int y)
Definition: eda_rect.h:192
std::vector< wxPoint > m_PolyPoints
Definition: lib_bezier.h:38
int compare(const LIB_ITEM &aOther, LIB_ITEM::COMPARE_FLAGS aCompareFlags=LIB_ITEM::COMPARE_FLAGS::NORMAL) const override
Provide the draw object specific comparison called by the == and < operators.
Definition: lib_bezier.cpp:56
#define MINIMUM_SELECTION_DISTANCE
Definition: lib_item.h:47
bool m_isFillable
Definition: lib_item.h:94
Define a library symbol object.
#define STRUCT_DELETED
flag indication structures to be erased
Definition: base_struct.h:126
void GetMsgPanelInfo(EDA_DRAW_FRAME *aFrame, std::vector< MSG_PANEL_ITEM > &aList) override
Display basic info (type, part and convert) about the current item in message panel.
Definition: lib_item.cpp:52
EDA_ITEM * Clone() const override
Function Clone creates a duplicate of this item with linked list members set to NULL.
Definition: lib_bezier.cpp:50
wxString MessageTextFromValue(EDA_UNITS aUnits, int aValue, bool aUseMils, EDA_DATA_TYPE aType)
Definition: base_units.cpp:124
Base plotter engine class.
Definition: plotter.h:114
Bezier curves to polygon converter.
Definition: bezier_curves.h:35
Definition: color4d.h:56
RENDER_SETTINGS * RenderSettings()
Definition: plotter.h:147
#define _(s)
Definition: 3d_actions.cpp:33
FILL_T m_Fill
The body fill type.
Definition: lib_item.h:93
STATUS_FLAGS m_Flags
Definition: base_struct.h:176
EDA_RECT handles the component boundary box.
Definition: eda_rect.h:44
void MirrorVertical(const wxPoint &aCenter) override
Mirror the draw object along the MirrorVertical (Y) axis about aCenter point.
Definition: lib_bezier.cpp:132
EDA_ITEM is a base class for most all the KiCad significant classes, used in schematics and boards.
Definition: base_struct.h:159
bool Intersects(const EDA_RECT &aRect) const
Function Intersects tests for a common area between rectangles.
int GetDefaultPenWidth() const
int m_Width
Definition: lib_bezier.h:36
Message panel definition file.
virtual int compare(const LIB_ITEM &aOther, LIB_ITEM::COMPARE_FLAGS aCompareFlags=LIB_ITEM::COMPARE_FLAGS::NORMAL) const
Provide the draw object specific comparison called by the == and < operators.
Definition: lib_item.cpp:76
EDA_UNITS GetUserUnits() const
Return the user units currently in use.
EDA_RECT & Inflate(wxCoord dx, wxCoord dy)
Function Inflate inflates the rectangle horizontally by dx and vertically by dy.
int GetPenWidth() const override
Definition: lib_bezier.cpp:198
KICAD_T Type() const
Function Type()
Definition: base_struct.h:193
Define a bezier curve graphic body item.
Definition: lib_bezier.h:34
COLOR4D is the color representation with 4 components: red, green, blue, alpha.
Definition: color4d.h:99