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 <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 
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 )
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( 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  {
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, BLUE );
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, BROWN );
349 }
350 
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)
Definition: base_units.cpp:122
Common plot library 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
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:38
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:540
int color
Definition: DXF_plotter.cpp:60
const EDA_RECT GetBoundingBox() const override
Function GetBoundingBox returns 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
Function HitTest tests if aPosition is contained within or on the bounding box of an item.
Definition: lib_bezier.cpp:244
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:162
Definition: color4d.h:62
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
virtual void PlotPoly(const std::vector< wxPoint > &aCornerList, FILL_TYPE aFill, int aWidth=USE_DEFAULT_LINE_WIDTH, void *aData=NULL)=0
Function PlotPoly.
void RotatePoint(int *pX, int *pY, double angle)
Definition: trigo.cpp:208
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:331
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:351
bool Contains(const wxPoint &aPoint) const
Function Contains.
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 components.
Definition: lib_item.h:62
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
FILL_TYPE m_Fill
The body fill type.
Definition: lib_item.h:94
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:80
FILL_TYPE GetFillMode() const
Definition: lib_item.h:302
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
void print(RENDER_SETTINGS *aSettings, const wxPoint &aOffset, void *aData, const TRANSFORM &aTransform) override
Print the item to aDC.
Definition: lib_bezier.cpp:205
#define NULL
COMPARE_FLAGS
The list of flags used by the compare function.
Definition: lib_item.h:117
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:53
#define MINIMUM_SELECTION_DISTANCE
Definition: lib_item.h:48
bool m_isFillable
Definition: lib_item.h:95
Define a library symbol object.
#define STRUCT_DELETED
flag indication structures to be erased
Definition: eda_item.h:114
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
EDA_ITEM * Clone() const override
Function Clone creates a duplicate of this item with linked list members set to NULL.
Definition: lib_bezier.cpp:47
Base plotter engine class.
Definition: plotter.h:120
Bezier curves to polygon converter.
Definition: bezier_curves.h:35
Definition: color4d.h:57
RENDER_SETTINGS * RenderSettings()
Definition: plotter.h:153
#define _(s)
Definition: 3d_actions.cpp:33
STATUS_FLAGS m_Flags
Definition: eda_item.h:164
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:129
EDA_ITEM is a base class for most all the KiCad significant classes, used in schematics and boards.
Definition: eda_item.h:147
bool Intersects(const EDA_RECT &aRect) const
Function Intersects tests for a common area between rectangles.
Definition: eda_rect.cpp:150
int GetDefaultPenWidth() const
#define SKIP_STRUCT
flag indicating that the structure should be ignored
Definition: eda_item.h:116
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:74
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.
Definition: eda_rect.cpp:363
int GetPenWidth() const override
Definition: lib_bezier.cpp:195
KICAD_T Type() const
Function Type()
Definition: eda_item.h:181
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:100