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