KiCad PCB EDA Suite
GRAPHICS_CLEANER Class Reference

#include <graphics_cleaner.h>

Public Member Functions

 GRAPHICS_CLEANER (DRAWINGS &aDrawings, MODULE *aParentModule, BOARD_COMMIT &aCommit)
 
void CleanupBoard (bool aDryRun, std::vector< std::shared_ptr< CLEANUP_ITEM > > *aItemsList, bool aMergeRects, bool aDeleteRedundant)
 the cleanup function. More...
 

Private Member Functions

bool isNullSegment (DRAWSEGMENT *aSegment)
 
bool areEquivalent (DRAWSEGMENT *aSegment1, DRAWSEGMENT *aSegment2)
 
void cleanupSegments ()
 
void mergeRects ()
 

Private Attributes

DRAWINGS & m_drawings
 
MODULEm_parentModule
 
BOARD_COMMITm_commit
 
bool m_dryRun
 
std::vector< std::shared_ptr< CLEANUP_ITEM > > * m_itemsList
 

Detailed Description

Definition at line 35 of file graphics_cleaner.h.

Constructor & Destructor Documentation

◆ GRAPHICS_CLEANER()

GRAPHICS_CLEANER::GRAPHICS_CLEANER ( DRAWINGS &  aDrawings,
MODULE aParentModule,
BOARD_COMMIT aCommit 
)

Definition at line 35 of file graphics_cleaner.cpp.

36  :
37  m_drawings( aDrawings ),
38  m_parentModule( aParentModule ),
39  m_commit( aCommit ),
40  m_dryRun( true ),
41  m_itemsList( nullptr )
42 {
43 }
BOARD_COMMIT & m_commit
std::vector< std::shared_ptr< CLEANUP_ITEM > > * m_itemsList
DRAWINGS & m_drawings

Member Function Documentation

◆ areEquivalent()

bool GRAPHICS_CLEANER::areEquivalent ( DRAWSEGMENT aSegment1,
DRAWSEGMENT aSegment2 
)
private

Definition at line 98 of file graphics_cleaner.cpp.

99 {
100  if( aSegment1->GetShape() != aSegment2->GetShape()
101  || aSegment1->GetLayer() != aSegment2->GetLayer()
102  || aSegment1->GetWidth() != aSegment2->GetWidth() )
103  {
104  return false;
105  }
106 
107  switch( aSegment1->GetShape() )
108  {
109  case S_SEGMENT:
110  case S_RECT:
111  case S_CIRCLE:
112  return aSegment1->GetStart() == aSegment2->GetStart()
113  && aSegment1->GetEnd() == aSegment2->GetEnd();
114 
115  case S_ARC:
116  return aSegment1->GetCenter() == aSegment2->GetCenter()
117  && aSegment1->GetArcStart() == aSegment2->GetArcStart()
118  && aSegment1->GetAngle() == aSegment2->GetAngle();
119 
120  case S_POLYGON:
121  // TODO
122  return false;
123 
124  case S_CURVE:
125  return aSegment1->GetBezControl1() == aSegment2->GetBezControl1()
126  && aSegment1->GetBezControl2() == aSegment2->GetBezControl2()
127  && aSegment1->GetBezierPoints() == aSegment2->GetBezierPoints();
128 
129  default:
130  wxFAIL_MSG( "GRAPHICS_CLEANER::areEquivalent unsupported DRAWSEGMENT shape: "
131  + STROKE_T_asString( aSegment1->GetShape() ) );
132  return false;
133  }
134 }
wxPoint GetArcStart() const
STROKE_T GetShape() const
polygon (not yet used for tracks, but could be in microwave apps)
usual segment : line with rounded ends
const std::vector< wxPoint > & GetBezierPoints() const
const wxPoint & GetEnd() const
Function GetEnd returns the ending point of the graphic.
segment with non rounded ends
Arcs (with rounded ends)
Bezier Curve.
int GetWidth() const
static wxString STROKE_T_asString(STROKE_T a)
double GetAngle() const
const wxPoint & GetBezControl2() const
const wxPoint & GetBezControl1() const
const wxPoint & GetStart() const
Function GetStart returns the starting point of the graphic.
virtual PCB_LAYER_ID GetLayer() const
Function GetLayer returns the primary layer this item is on.
wxPoint GetCenter() const override
Function GetCenter()

References DRAWSEGMENT::GetAngle(), DRAWSEGMENT::GetArcStart(), DRAWSEGMENT::GetBezControl1(), DRAWSEGMENT::GetBezControl2(), DRAWSEGMENT::GetBezierPoints(), DRAWSEGMENT::GetCenter(), DRAWSEGMENT::GetEnd(), BOARD_ITEM::GetLayer(), DRAWSEGMENT::GetShape(), DRAWSEGMENT::GetStart(), DRAWSEGMENT::GetWidth(), S_ARC, S_CIRCLE, S_CURVE, S_POLYGON, S_RECT, S_SEGMENT, and STROKE_T_asString().

Referenced by cleanupSegments().

◆ CleanupBoard()

void GRAPHICS_CLEANER::CleanupBoard ( bool  aDryRun,
std::vector< std::shared_ptr< CLEANUP_ITEM > > *  aItemsList,
bool  aMergeRects,
bool  aDeleteRedundant 
)

the cleanup function.

Parameters
aMergeRects= merge for segments forming a rectangle into a rect
aDeleteRedundant= true to delete null graphics and duplicated graphics

Definition at line 46 of file graphics_cleaner.cpp.

48 {
49  m_dryRun = aDryRun;
50  m_itemsList = aItemsList;
51 
52  // Clear the flag used to mark some segments as deleted, in dry run:
53  for( BOARD_ITEM* drawing : m_drawings )
54  drawing->ClearFlags( IS_DELETED );
55 
56  if( aDeleteRedundant )
58 
59  if( aMergeRects )
60  mergeRects();
61 
62  // Clear the flag used to mark some segments:
63  for( BOARD_ITEM* drawing : m_drawings )
64  drawing->ClearFlags( IS_DELETED );
65 }
BOARD_ITEM is a base class for any item which can be embedded within the BOARD container class,...
std::vector< std::shared_ptr< CLEANUP_ITEM > > * m_itemsList
#define IS_DELETED
Definition: base_struct.h:120
DRAWINGS & m_drawings

References cleanupSegments(), IS_DELETED, m_drawings, m_dryRun, m_itemsList, and mergeRects().

◆ cleanupSegments()

void GRAPHICS_CLEANER::cleanupSegments ( )
private

Definition at line 137 of file graphics_cleaner.cpp.

138 {
139  // Remove duplicate segments (2 superimposed identical segments):
140  for( auto it = m_drawings.begin(); it != m_drawings.end(); it++ )
141  {
142  DRAWSEGMENT* segment = dynamic_cast<DRAWSEGMENT*>( *it );
143 
144  if( !segment || segment->GetShape() != S_SEGMENT || segment->HasFlag( IS_DELETED ) )
145  continue;
146 
147  if( isNullSegment( segment ) )
148  {
149  std::shared_ptr<CLEANUP_ITEM> item( new CLEANUP_ITEM( CLEANUP_NULL_GRAPHIC ) );
150  item->SetItems( segment );
151  m_itemsList->push_back( item );
152 
153  if( !m_dryRun )
154  m_commit.Removed( segment );
155 
156  continue;
157  }
158 
159  for( auto it2 = it + 1; it2 != m_drawings.end(); it2++ )
160  {
161  DRAWSEGMENT* segment2 = dynamic_cast<DRAWSEGMENT*>( *it2 );
162 
163  if( !segment2 || segment2->HasFlag( IS_DELETED ) )
164  continue;
165 
166  if( areEquivalent( segment, segment2 ) )
167  {
168  std::shared_ptr<CLEANUP_ITEM> item( new CLEANUP_ITEM( CLEANUP_DUPLICATE_GRAPHIC ) );
169  item->SetItems( segment2 );
170  m_itemsList->push_back( item );
171 
172  segment2->SetFlags( IS_DELETED );
173 
174  if( !m_dryRun )
175  m_commit.Removed( segment2 );
176  }
177  }
178  }
179 }
BOARD_COMMIT & m_commit
bool isNullSegment(DRAWSEGMENT *aSegment)
STROKE_T GetShape() const
std::vector< std::shared_ptr< CLEANUP_ITEM > > * m_itemsList
usual segment : line with rounded ends
COMMIT & Removed(EDA_ITEM *aItem)
Notifies observers that aItem has been removed
Definition: commit.h:96
void SetFlags(STATUS_FLAGS aMask)
Definition: base_struct.h:232
#define IS_DELETED
Definition: base_struct.h:120
bool areEquivalent(DRAWSEGMENT *aSegment1, DRAWSEGMENT *aSegment2)
bool HasFlag(STATUS_FLAGS aFlag)
Definition: base_struct.h:235
DRAWINGS & m_drawings

References areEquivalent(), CLEANUP_DUPLICATE_GRAPHIC, CLEANUP_NULL_GRAPHIC, DRAWSEGMENT::GetShape(), EDA_ITEM::HasFlag(), IS_DELETED, isNullSegment(), m_commit, m_drawings, m_dryRun, m_itemsList, COMMIT::Removed(), S_SEGMENT, and EDA_ITEM::SetFlags().

Referenced by CleanupBoard().

◆ isNullSegment()

bool GRAPHICS_CLEANER::isNullSegment ( DRAWSEGMENT aSegment)
private

Definition at line 68 of file graphics_cleaner.cpp.

69 {
70  switch( aSegment->GetShape() )
71  {
72  case S_SEGMENT:
73  case S_RECT:
74  return aSegment->GetStart() == aSegment->GetEnd();
75 
76  case S_CIRCLE:
77  return aSegment->GetRadius() == 0;
78 
79  case S_ARC:
80  return aSegment->GetCenter().x == aSegment->GetArcStart().x
81  && aSegment->GetCenter().y == aSegment->GetArcStart().y;
82 
83  case S_POLYGON:
84  return aSegment->GetPointCount() == 0;
85 
86  case S_CURVE:
87  aSegment->RebuildBezierToSegmentsPointsList( aSegment->GetWidth() );
88  return aSegment->GetBezierPoints().empty();
89 
90  default:
91  wxFAIL_MSG( "GRAPHICS_CLEANER::isNullSegment unsupported DRAWSEGMENT shape: "
92  + STROKE_T_asString( aSegment->GetShape() ) );
93  return false;
94  }
95 }
wxPoint GetArcStart() const
STROKE_T GetShape() const
polygon (not yet used for tracks, but could be in microwave apps)
void RebuildBezierToSegmentsPointsList(int aMinSegLen)
Rebuild the m_BezierPoints vertex list that approximate the Bezier curve by a list of segments Has me...
usual segment : line with rounded ends
const std::vector< wxPoint > & GetBezierPoints() const
const wxPoint & GetEnd() const
Function GetEnd returns the ending point of the graphic.
segment with non rounded ends
Arcs (with rounded ends)
int GetRadius() const
Function GetRadius returns the radius of this item Has meaning only for arc and circle.
Bezier Curve.
int GetPointCount() const
int GetWidth() const
static wxString STROKE_T_asString(STROKE_T a)
const wxPoint & GetStart() const
Function GetStart returns the starting point of the graphic.
wxPoint GetCenter() const override
Function GetCenter()

References DRAWSEGMENT::GetArcStart(), DRAWSEGMENT::GetBezierPoints(), DRAWSEGMENT::GetCenter(), DRAWSEGMENT::GetEnd(), DRAWSEGMENT::GetPointCount(), DRAWSEGMENT::GetRadius(), DRAWSEGMENT::GetShape(), DRAWSEGMENT::GetStart(), DRAWSEGMENT::GetWidth(), DRAWSEGMENT::RebuildBezierToSegmentsPointsList(), S_ARC, S_CIRCLE, S_CURVE, S_POLYGON, S_RECT, S_SEGMENT, STROKE_T_asString(), wxPoint::x, and wxPoint::y.

Referenced by cleanupSegments().

◆ mergeRects()

void GRAPHICS_CLEANER::mergeRects ( )
private

Definition at line 182 of file graphics_cleaner.cpp.

183 {
184  struct SIDE_CANDIDATE
185  {
186  SIDE_CANDIDATE( DRAWSEGMENT* aSeg ) :
187  start( aSeg->GetStart() ),
188  end( aSeg->GetEnd() ),
189  seg( aSeg )
190  {
191  if( start.x > end.x || start.y > end.y )
192  std::swap( start, end );
193  }
194 
195  wxPoint start;
196  wxPoint end;
197  DRAWSEGMENT* seg;
198  };
199 
200  std::vector<SIDE_CANDIDATE*> sides;
201  std::map<wxPoint, std::vector<SIDE_CANDIDATE*>> ptMap;
202 
203  // First load all the candidates into the side vector and layer maps
204  for( BOARD_ITEM* item : m_drawings )
205  {
206  DRAWSEGMENT* seg = dynamic_cast<DRAWSEGMENT*>( item );
207 
208  if( !seg || seg->GetShape() != S_SEGMENT )
209  continue;
210 
211  if( seg->GetStart().x == seg->GetEnd().x || seg->GetStart().y == seg->GetEnd().y )
212  {
213  sides.emplace_back( new SIDE_CANDIDATE( seg ) );
214  ptMap[ sides.back()->start ].push_back( sides.back() );
215  }
216  }
217 
218  // Now go through the sides and try and match lines into rectangles
219  for( SIDE_CANDIDATE* side : sides )
220  {
221  if( side->seg->HasFlag( IS_DELETED ) )
222  continue;
223 
224  SIDE_CANDIDATE* left = nullptr;
225  SIDE_CANDIDATE* top = nullptr;
226  SIDE_CANDIDATE* right = nullptr;
227  SIDE_CANDIDATE* bottom = nullptr;
228 
229  auto viable = [&]( SIDE_CANDIDATE* aCandidate ) -> bool
230  {
231  return aCandidate->seg->GetLayer() == side->seg->GetLayer()
232  && aCandidate->seg->GetWidth() == side->seg->GetWidth()
233  && !aCandidate->seg->HasFlag( IS_DELETED );
234  };
235 
236  if( side->start.x == side->end.x )
237  {
238  // We've found a possible left; see if we have a top
239  //
240  left = side;
241 
242  for( SIDE_CANDIDATE* candidate : ptMap[ left->start ] )
243  {
244  if( candidate != left && viable( candidate ) )
245  {
246  top = candidate;
247  break;
248  }
249  }
250  }
251  else if( side->start.y == side->end.y )
252  {
253  // We've found a possible top; see if we have a left
254  //
255  top = side;
256 
257  for( SIDE_CANDIDATE* candidate : ptMap[ top->start ] )
258  {
259  if( candidate != top && viable( candidate ) )
260  {
261  left = candidate;
262  break;
263  }
264  }
265  }
266 
267  if( top && left )
268  {
269  // See if we can fill in the other two sides
270  //
271  for( SIDE_CANDIDATE* candidate : ptMap[ top->end ] )
272  {
273  if( candidate != top && viable( candidate ) )
274  {
275  right = candidate;
276  break;
277  }
278  }
279 
280  for( SIDE_CANDIDATE* candidate : ptMap[ left->end ] )
281  {
282  if( candidate != left && viable( candidate ) )
283  {
284  bottom = candidate;
285  break;
286  }
287  }
288 
289  if( right && bottom && right->end == bottom->end )
290  {
291  left->seg->SetFlags( IS_DELETED );
292  top->seg->SetFlags( IS_DELETED );
293  right->seg->SetFlags( IS_DELETED );
294  bottom->seg->SetFlags( IS_DELETED );
295 
296  std::shared_ptr<CLEANUP_ITEM> item( new CLEANUP_ITEM( CLEANUP_LINES_TO_RECT ) );
297  item->SetItems( left->seg, top->seg, right->seg, bottom->seg );
298  m_itemsList->push_back( item );
299 
300  if( !m_dryRun )
301  {
302  DRAWSEGMENT* rect;
303 
304  if( m_parentModule )
305  rect = new EDGE_MODULE( m_parentModule );
306  else
307  rect = new DRAWSEGMENT();
308 
309  rect->SetShape( S_RECT );
310  rect->SetStart( top->start );
311  rect->SetEnd( bottom->end );
312  rect->SetLayer( top->seg->GetLayer() );
313  rect->SetWidth( top->seg->GetWidth() );
314 
315  m_commit.Add( rect );
316  m_commit.Remove( left->seg );
317  m_commit.Remove( top->seg );
318  m_commit.Remove( right->seg );
319  m_commit.Remove( bottom->seg );
320  }
321  }
322  }
323  }
324 
325  for( SIDE_CANDIDATE* side : sides )
326  delete side;
327 }
BOARD_COMMIT & m_commit
void SetShape(STROKE_T aShape)
virtual void SetLayer(PCB_LAYER_ID aLayer)
Function SetLayer sets the layer this item is on.
BOARD_ITEM is a base class for any item which can be embedded within the BOARD container class,...
COMMIT & Add(EDA_ITEM *aItem)
Adds a new item to the model
Definition: commit.h:78
STROKE_T GetShape() const
std::vector< std::shared_ptr< CLEANUP_ITEM > > * m_itemsList
usual segment : line with rounded ends
const wxPoint & GetEnd() const
Function GetEnd returns the ending point of the graphic.
segment with non rounded ends
#define IS_DELETED
Definition: base_struct.h:120
COMMIT & Remove(EDA_ITEM *aItem)
Removes a new item from the model
Definition: commit.h:90
void SetStart(const wxPoint &aStart)
void SetEnd(const wxPoint &aEnd)
const wxPoint & GetStart() const
Function GetStart returns the starting point of the graphic.
DRAWINGS & m_drawings
void SetWidth(int aWidth)

References COMMIT::Add(), CLEANUP_LINES_TO_RECT, DRAWSEGMENT::GetEnd(), DRAWSEGMENT::GetShape(), DRAWSEGMENT::GetStart(), IS_DELETED, m_commit, m_drawings, m_dryRun, m_itemsList, m_parentModule, COMMIT::Remove(), S_RECT, S_SEGMENT, DRAWSEGMENT::SetEnd(), BOARD_ITEM::SetLayer(), DRAWSEGMENT::SetShape(), DRAWSEGMENT::SetStart(), DRAWSEGMENT::SetWidth(), wxPoint::x, and wxPoint::y.

Referenced by CleanupBoard().

Member Data Documentation

◆ m_commit

BOARD_COMMIT& GRAPHICS_CLEANER::m_commit
private

Definition at line 58 of file graphics_cleaner.h.

Referenced by cleanupSegments(), and mergeRects().

◆ m_drawings

DRAWINGS& GRAPHICS_CLEANER::m_drawings
private

Definition at line 56 of file graphics_cleaner.h.

Referenced by CleanupBoard(), cleanupSegments(), and mergeRects().

◆ m_dryRun

bool GRAPHICS_CLEANER::m_dryRun
private

Definition at line 59 of file graphics_cleaner.h.

Referenced by CleanupBoard(), cleanupSegments(), and mergeRects().

◆ m_itemsList

std::vector<std::shared_ptr<CLEANUP_ITEM> >* GRAPHICS_CLEANER::m_itemsList
private

Definition at line 60 of file graphics_cleaner.h.

Referenced by CleanupBoard(), cleanupSegments(), and mergeRects().

◆ m_parentModule

MODULE* GRAPHICS_CLEANER::m_parentModule
private

Definition at line 57 of file graphics_cleaner.h.

Referenced by mergeRects().


The documentation for this class was generated from the following files: