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-2021 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 <plotters/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 
101 const wxPoint LIB_BEZIER::GetOffset() const
102 {
103  if ( !m_PolyPoints.size() )
104  return wxPoint(0, 0);
105 
106  return m_PolyPoints[0];
107 }
108 
109 
110 void LIB_BEZIER::MirrorHorizontal( const wxPoint& aCenter )
111 {
112  size_t i, imax = m_PolyPoints.size();
113 
114  for( i = 0; i < imax; i++ )
115  {
116  m_PolyPoints[i].x -= aCenter.x;
117  m_PolyPoints[i].x *= -1;
118  m_PolyPoints[i].x += aCenter.x;
119  }
120 
121  imax = m_BezierPoints.size();
122 
123  for( i = 0; i < imax; i++ )
124  {
125  m_BezierPoints[i].x -= aCenter.x;
126  m_BezierPoints[i].x *= -1;
127  m_BezierPoints[i].x += aCenter.x;
128  }
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 
154 void LIB_BEZIER::Rotate( const wxPoint& aCenter, bool aRotateCCW )
155 {
156  int rot_angle = aRotateCCW ? -900 : 900;
157 
158  for( wxPoint& point : m_PolyPoints )
159  RotatePoint( &point, aCenter, rot_angle );
160 
161  for( wxPoint& bezierPoint : m_BezierPoints )
162  RotatePoint( &bezierPoint, aCenter, rot_angle );
163 }
164 
165 
166 void LIB_BEZIER::Plot( PLOTTER* aPlotter, const wxPoint& aOffset, bool aFill,
167  const TRANSFORM& aTransform ) const
168 {
169  wxASSERT( aPlotter != nullptr );
170 
171  static std::vector< wxPoint > cornerList;
172  cornerList.clear();
173 
174  for( wxPoint pos : m_PolyPoints )
175  {
176  pos = aTransform.TransformCoordinate( pos ) + aOffset;
177  cornerList.push_back( pos );
178  }
179 
181  {
182  aPlotter->SetColor( aPlotter->RenderSettings()->GetLayerColor( LAYER_DEVICE_BACKGROUND ) );
183  aPlotter->PlotPoly( cornerList, FILL_TYPE::FILLED_WITH_BG_BODYCOLOR, 0 );
184  }
185 
186  bool already_filled = m_fill == FILL_TYPE::FILLED_WITH_BG_BODYCOLOR;
187  int pen_size = GetEffectivePenWidth( aPlotter->RenderSettings() );
188 
189  if( !already_filled || pen_size > 0 )
190  {
191  aPlotter->SetColor( aPlotter->RenderSettings()->GetLayerColor( LAYER_DEVICE ) );
192  aPlotter->PlotPoly( cornerList, already_filled ? FILL_TYPE::NO_FILL : m_fill, pen_size );
193  }
194 }
195 
196 
198 {
199  return m_Width;
200 }
201 
202 
203 void LIB_BEZIER::print( const RENDER_SETTINGS* aSettings, const wxPoint& aOffset, void* aData,
204  const TRANSFORM& aTransform )
205 {
206  bool forceNoFill = static_cast<bool>( aData );
207  int penWidth = GetEffectivePenWidth( aSettings );
208 
209  if( forceNoFill && m_fill != FILL_TYPE::NO_FILL && penWidth == 0 )
210  return;
211 
212  std::vector<wxPoint> PolyPointsTraslated;
213 
214  wxDC* DC = aSettings->GetPrintDC();
215  COLOR4D color = aSettings->GetLayerColor( LAYER_DEVICE );
216  BEZIER_POLY converter( m_BezierPoints );
217  converter.GetPoly( m_PolyPoints );
218 
219  PolyPointsTraslated.clear();
220 
221  for( wxPoint& point : m_PolyPoints )
222  PolyPointsTraslated.push_back( aTransform.TransformCoordinate( point ) + aOffset );
223 
224  if( forceNoFill || m_fill == FILL_TYPE::NO_FILL )
225  {
226  GRPoly( nullptr, DC, m_PolyPoints.size(), &PolyPointsTraslated[0], false, penWidth,
227  color, color );
228  }
229  else
230  {
233 
234  GRPoly( nullptr, DC, m_PolyPoints.size(), &PolyPointsTraslated[0], true, penWidth,
235  color, color );
236  }
237 }
238 
239 
240 bool LIB_BEZIER::HitTest( const wxPoint& aRefPos, int aAccuracy ) const
241 {
242  int mindist = std::max( aAccuracy + GetPenWidth() / 2,
243  Mils2iu( MINIMUM_SELECTION_DISTANCE ) );
244  wxPoint start, end;
245 
246  for( unsigned ii = 1; ii < GetCornerCount(); ii++ )
247  {
250 
251  if ( TestSegmentHit( aRefPos, start, end, mindist ) )
252  return true;
253  }
254 
255  return false;
256 }
257 
258 
259 bool LIB_BEZIER::HitTest( const EDA_RECT& aRect, bool aContained, int aAccuracy ) const
260 {
261  if( m_flags & (STRUCT_DELETED | SKIP_STRUCT ) )
262  return false;
263 
264  EDA_RECT sel = aRect;
265 
266  if ( aAccuracy )
267  sel.Inflate( aAccuracy );
268 
269  if( aContained )
270  return sel.Contains( GetBoundingBox() );
271 
272  // Fast test: if aRect is outside the polygon bounding box, rectangles cannot intersect
273  if( !sel.Intersects( GetBoundingBox() ) )
274  return false;
275 
276  // Account for the width of the line
277  sel.Inflate( GetWidth() / 2 );
278  unsigned count = m_BezierPoints.size();
279 
280  for( unsigned ii = 1; ii < count; ii++ )
281  {
282  wxPoint vertex = DefaultTransform.TransformCoordinate( m_BezierPoints[ii-1] );
283  wxPoint vertexNext = DefaultTransform.TransformCoordinate( m_BezierPoints[ii] );
284 
285  // Test if the point is within aRect
286  if( sel.Contains( vertex ) )
287  return true;
288 
289  // Test if this edge intersects aRect
290  if( sel.Intersects( vertex, vertexNext ) )
291  return true;
292  }
293 
294  return false;
295 }
296 
297 
299 {
300  EDA_RECT rect;
301  int xmin, xmax, ymin, ymax;
302 
303  if( !GetCornerCount() )
304  return rect;
305 
306  xmin = xmax = m_PolyPoints[0].x;
307  ymin = ymax = m_PolyPoints[0].y;
308 
309  for( unsigned ii = 1; ii < GetCornerCount(); ii++ )
310  {
311  xmin = std::min( xmin, m_PolyPoints[ii].x );
312  xmax = std::max( xmax, m_PolyPoints[ii].x );
313  ymin = std::min( ymin, m_PolyPoints[ii].y );
314  ymax = std::max( ymax, m_PolyPoints[ii].y );
315  }
316 
317  rect.SetOrigin( xmin, ymin );
318  rect.SetEnd( xmax, ymax );
319  rect.Inflate( ( GetPenWidth() / 2 ) + 1 );
320 
321  rect.RevertYAxis();
322 
323  return rect;
324 }
325 
326 
327 void LIB_BEZIER::GetMsgPanelInfo( EDA_DRAW_FRAME* aFrame, std::vector<MSG_PANEL_ITEM>& aList )
328 {
329  wxString msg;
330  EDA_RECT bBox = GetBoundingBox();
331 
332  LIB_ITEM::GetMsgPanelInfo( aFrame, aList );
333 
334  msg = MessageTextFromValue( aFrame->GetUserUnits(), m_Width );
335 
336  aList.emplace_back( _( "Line Width" ), msg );
337 
338  msg.Printf( wxT( "(%d, %d, %d, %d)" ),
339  bBox.GetOrigin().x,
340  bBox.GetOrigin().y,
341  bBox.GetEnd().x,
342  bBox.GetEnd().y );
343 
344  aList.emplace_back( _( "Bounding Box" ), msg );
345 }
346 
347 wxPoint LIB_BEZIER::GetPosition() const
348 {
349  if( !m_PolyPoints.size() )
350  return wxPoint(0, 0);
351 
352  return m_PolyPoints[0];
353 }
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:104
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:101
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.
int color
Definition: DXF_plotter.cpp:57
const EDA_RECT GetBoundingBox() const override
Return the orthogonal bounding box of this object for display purposes.
Definition: lib_bezier.cpp:298
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:240
const COLOR4D & GetLayerColor(int aLayer) const
Return the color used to draw a layer.
void SetOrigin(const wxPoint &pos)
Definition: eda_rect.h:121
virtual int GetEffectivePenWidth(const RENDER_SETTINGS *aSettings) const
Definition: lib_item.h:146
EDA_ITEM_FLAGS m_flags
Definition: eda_item.h:481
void RotatePoint(int *pX, int *pY, double angle)
Definition: trigo.cpp:229
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:327
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:347
FILL_TYPE m_fill
The body fill type.
Definition: lib_item.h:339
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
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:203
void MirrorHorizontal(const wxPoint &aCenter) override
Mirror the draw object along the horizontal (X) axis about aCenter point.
Definition: lib_bezier.cpp:110
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:154
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:166
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
bool TestSegmentHit(const wxPoint &aRefPoint, const wxPoint &aStart, const wxPoint &aEnd, int aDist)
Test if aRefPoint is with aDistance on the line defined by aStart and aEnd.
Definition: trigo.cpp:129
#define MINIMUM_SELECTION_DISTANCE
Definition: lib_item.h:47
bool m_isFillable
Definition: lib_item.h:340
#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:132
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
void GRPoly(EDA_RECT *ClipBox, wxDC *DC, int n, const wxPoint *Points, bool Fill, int width, const COLOR4D &Color, const COLOR4D &BgColor)
Draw a new polyline and fill it if Fill, in drawing space.
Definition: gr_basic.cpp:497
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:197
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