KiCad PCB EDA Suite
bus-wire-junction.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 Jean-Pierre Charras, jean-pierre.charras@gipsa-lab.inpg.fr
5  * Copyright (C) 2004-2016 KiCad Developers, see change_log.txt for contributors.
6  *
7  * This program is free software; you can redistribute it and/or
8  * modify it under the terms of the GNU General Public License
9  * as published by the Free Software Foundation; either version 2
10  * of the License, or (at your option) any later version.
11  *
12  * This program is distributed in the hope that it will be useful,
13  * but WITHOUT ANY WARRANTY; without even the implied warranty of
14  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15  * GNU General Public License for more details.
16  *
17  * You should have received a copy of the GNU General Public License
18  * along with this program; if not, you may find one here:
19  * http://www.gnu.org/licenses/old-licenses/gpl-2.0.html
20  * or you may search the http://www.gnu.org website for the version 2 license,
21  * or you may write to the Free Software Foundation, Inc.,
22  * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA
23  */
24 
30 #include <fctsys.h>
31 #include <gr_basic.h>
32 #include <sch_draw_panel.h>
33 #include <sch_edit_frame.h>
34 
35 #include <lib_draw_item.h>
36 #include <lib_pin.h>
37 #include <general.h>
38 #include <sch_bus_entry.h>
39 #include <sch_junction.h>
40 #include <sch_line.h>
41 #include <sch_no_connect.h>
42 #include <sch_text.h>
43 #include <sch_component.h>
44 #include <sch_sheet.h>
45 #include <sch_view.h>
46 #include <view/view_group.h>
47 
48 
49 
50 static void AbortCreateNewLine( EDA_DRAW_PANEL* aPanel, wxDC* aDC );
51 static void ComputeBreakPoint( SCH_SCREEN* aScreen, SCH_LINE* aSegment, wxPoint& new_pos );
52 
53 static DLIST< SCH_ITEM > s_wires; // when creating a new set of wires,
54  // stores here the new wires.
55 
56 
70 static void RemoveBacktracks( DLIST<SCH_ITEM>& aWires )
71 {
72  EDA_ITEM* first = aWires.GetFirst();
73  std::vector<SCH_LINE*> last_lines;
74 
75  for( EDA_ITEM* p = first; p; )
76  {
77  SCH_LINE *line = static_cast<SCH_LINE*>( p );
78  p = line->Next();
79 
80  if( line->IsNull() )
81  {
82  delete s_wires.Remove( line );
83  continue;
84  }
85 
86  if( !last_lines.empty() )
87  {
88  SCH_LINE* last_line = last_lines[last_lines.size() - 1];
89  bool contiguous = ( last_line->GetEndPoint() == line->GetStartPoint() );
90  bool backtracks = IsPointOnSegment( last_line->GetStartPoint(),
91  last_line->GetEndPoint(), line->GetEndPoint() );
92  bool total_backtrack = ( last_line->GetStartPoint() == line->GetEndPoint() );
93 
94  if( contiguous && backtracks )
95  {
96  if( total_backtrack )
97  {
98  delete s_wires.Remove( last_line );
99  delete s_wires.Remove( line );
100  last_lines.pop_back();
101  }
102  else
103  {
104  last_line->SetEndPoint( line->GetEndPoint() );
105  delete s_wires.Remove( line );
106  }
107  }
108  else
109  {
110  last_lines.push_back( line );
111  }
112  }
113  else
114  {
115  last_lines.push_back( line );
116  }
117  }
118 }
119 
120 
124 static void DrawSegment( EDA_DRAW_PANEL* aPanel, wxDC* aDC, const wxPoint& aPosition, bool aErase )
125 {
126  if( s_wires.GetCount() == 0 )
127  return;
128 
129  SCH_EDIT_FRAME* frame = (SCH_EDIT_FRAME*) aPanel->GetParent();
130 
131  wxPoint endpos = frame->GetCrossHairPosition();
132 
133  if( frame->GetForceHVLines() ) /* Coerce the line to vertical or horizontal one: */
134  ComputeBreakPoint( frame->GetScreen(), (SCH_LINE*) s_wires.GetLast()->Back(), endpos );
135  else
136  ( (SCH_LINE*) s_wires.GetLast() )->SetEndPoint( endpos );
137 
138  auto view = static_cast<SCH_DRAW_PANEL*>( aPanel )->GetView();
139 
140  view->ClearPreview();
141 
142  for( SCH_LINE* segment = (SCH_LINE*) s_wires.begin(); segment; segment = segment->Next() )
143  {
144  if( !segment->IsNull() ) // Add to preview if segment length != 0
145  view->AddToPreview( segment->Clone() );
146  }
147 }
148 
149 
151 {
152  SCH_LINE* segment;
153  SCH_LINE* nextSegment;
154  wxPoint cursorpos = GetCrossHairPosition();
155 
156  // We should know if a segment is currently in progress
157  segment = (SCH_LINE*) GetScreen()->GetCurItem();
158  if( segment ) // a current item exists, but not necessary a currently edited item
159  {
160  if( !segment->GetFlags() || ( segment->Type() != SCH_LINE_T ) )
161  {
162  if( segment->GetFlags() )
163  wxLogDebug( wxT( "BeginSegment: item->GetFlags()== %X" ), segment->GetFlags() );
164 
165  // no wire, bus or graphic line in progress
166  segment = NULL;
167  }
168  }
169 
170  if( !segment ) // first point : Create the first wire or bus segment
171  {
172  switch( type )
173  {
174  default:
175  segment = new SCH_LINE( cursorpos, LAYER_NOTES );
176  break;
177 
178  case LAYER_WIRE:
179  segment = new SCH_LINE( cursorpos, LAYER_WIRE );
180 
181  /* A junction will be created later, when we'll know the
182  * segment end position, and if the junction is really needed */
183  break;
184 
185  case LAYER_BUS:
186  segment = new SCH_LINE( cursorpos, LAYER_BUS );
187  break;
188  }
189 
190  segment->SetFlags( IS_NEW );
191  s_wires.PushBack( segment );
192  GetScreen()->SetCurItem( segment );
193 
194  // We need 2 segments to go from a given start pin to an end point when the horizontal
195  // and vertical lines only switch is on.
196  if( GetForceHVLines() )
197  {
198  nextSegment = new SCH_LINE( *segment );
199  nextSegment->SetFlags( IS_NEW );
200  s_wires.PushBack( nextSegment );
201  GetScreen()->SetCurItem( nextSegment );
202  }
203 
205  SetRepeatItem( NULL );
206  }
207  else // A segment is in progress: terminates the current segment and add a new segment.
208  {
209  SCH_LINE* prevSegment = segment->Back();
210 
211  // Be aware prevSegment can be null when the horizontal and vertical lines only switch is off
212  // when we create the first segment.
213 
214  if( !GetForceHVLines() )
215  {
216  // If only one segment is needed and it has a zero length, do not create a new one.
217  if( segment->IsNull() )
218  return;
219  }
220  else
221  {
222  wxCHECK_RET( prevSegment != NULL, wxT( "Failed to create second line segment." ) );
223 
224  // If two segments are required and they both have zero length, do not
225  // create a new one.
226  if( prevSegment && prevSegment->IsNull() && segment->IsNull() )
227  return;
228  }
229 
230  m_canvas->CallMouseCapture( nullptr, wxDefaultPosition, false );
231 
232  // Terminate the command if the end point is on a pin, junction, or another wire or bus.
233  if( GetScreen()->IsTerminalPoint( cursorpos, segment->GetLayer() ) )
234  {
235  EndSegment();
236  return;
237  }
238 
239  // Create a new segment, and chain it after the current new segment.
240  nextSegment = new SCH_LINE( *segment );
241  nextSegment->SetStartPoint( cursorpos );
242  s_wires.PushBack( nextSegment );
243 
244  segment->SetEndPoint( cursorpos );
245  segment->ClearFlags( IS_NEW );
246  segment->SetFlags( SELECTED );
247  nextSegment->SetFlags( IS_NEW );
248  GetScreen()->SetCurItem( nextSegment );
249  m_canvas->CallMouseCapture( nullptr, wxDefaultPosition, false );
250  }
251 }
252 
253 
254 void SCH_EDIT_FRAME::GetSchematicConnections( std::vector< wxPoint >& aConnections )
255 {
256  for( SCH_ITEM* item = GetScreen()->GetDrawItems(); item; item = item->Next() )
257  {
258  // Avoid items that are changing
259  if( !( item->GetFlags() & ( IS_DRAGGED | IS_MOVED | IS_DELETED ) ) )
260  item->GetConnectionPoints( aConnections );
261  }
262 
263  // We always have some overlapping connection points. Drop duplicates here
264  std::sort( aConnections.begin(), aConnections.end(),
265  []( const wxPoint& a, const wxPoint& b ) -> bool
266  { return a.x < b.x || (a.x == b.x && a.y < b.y); } );
267  aConnections.erase( unique( aConnections.begin(), aConnections.end() ), aConnections.end() );
268 }
269 
270 
272 {
273  std::vector<DANGLING_END_ITEM> endPoints;
274  bool hasStateChanged = false;
275 
276  for( SCH_ITEM* item = GetScreen()->GetDrawList().begin(); item; item = item->Next() )
277  item->GetEndPoints( endPoints );
278 
279  for( SCH_ITEM* item = GetScreen()->GetDrawList().begin(); item; item = item->Next() )
280  {
281  if( item->IsDanglingStateChanged( endPoints ) )
282  {
283  GetCanvas()->GetView()->Update( item, KIGFX::REPAINT );
284  hasStateChanged = true;
285  }
286  }
287 
288  return hasStateChanged;
289 }
290 
291 
293 {
294  SCH_SCREEN* screen = GetScreen();
295  SCH_LINE* segment = (SCH_LINE*) screen->GetCurItem();
296  PICKED_ITEMS_LIST itemList;
297 
298  if( segment == NULL || segment->Type() != SCH_LINE_T || !segment->IsNew() )
299  return;
300 
301  // Remove segments backtracking over others
302  RemoveBacktracks( s_wires );
303 
304  if( s_wires.GetCount() == 0 )
305  return;
306 
307  // Collect the possible connection points for the new lines
308  std::vector< wxPoint > connections;
309  std::vector< wxPoint > new_ends;
310  GetSchematicConnections( connections );
311 
312  // Check each new segment for possible junctions and add/split if needed
313  for( SCH_ITEM* wire = s_wires.GetFirst(); wire; wire=wire->Next() )
314  {
315  SCH_LINE* test_line = (SCH_LINE*) wire;
316  if( wire->GetFlags() & SKIP_STRUCT )
317  continue;
318 
319  wire->GetConnectionPoints( new_ends );
320 
321  for( auto i : connections )
322  {
323  if( IsPointOnSegment( test_line->GetStartPoint(), test_line->GetEndPoint(), i ) )
324  {
325  new_ends.push_back( i );
326  }
327  }
328  itemList.PushItem( ITEM_PICKER( wire, UR_NEW ) );
329  }
330 
331  // Get the last non-null wire (this is the last created segment).
332  SetRepeatItem( segment = (SCH_LINE*) s_wires.GetLast() );
333 
334  // Add the new wires
335  AddToScreen( s_wires );
336 
337  auto view = GetCanvas()->GetView();
338  view->ClearPreview();
339  view->ShowPreview( false );
340  view->ClearHiddenFlags();
341 
342  SaveCopyInUndoList(itemList, UR_NEW);
343 
344  // Correct and remove segments that need to be merged.
345  SchematicCleanUp( true );
346 
347  for( auto item = GetScreen()->GetDrawItems(); item; item = item->Next() )
348  {
349  if( item->Type() != SCH_COMPONENT_T )
350  continue;
351 
352  std::vector< wxPoint > pts;
353  item->GetConnectionPoints( pts );
354 
355  if( pts.size() > 2 )
356  continue;
357 
358  // Do not trim wires that connect directly to an endpoint
359  pts.erase( std::remove_if( pts.begin(), pts.end(), [ &segment ]( const wxPoint& aPt )
360  { return segment->IsEndPoint( aPt ); } ), pts.end() );
361 
362  for( auto i = pts.begin(); i != pts.end(); i++ )
363  for( auto j = i + 1; j != pts.end(); j++ )
364  TrimWire( *i, *j, true );
365  }
366 
367  for( auto i : new_ends )
368  {
369  if( screen->IsJunctionNeeded( i, true ) )
370  AddJunction( i, true );
371  }
372 
374  screen->ClearDrawingState();
375  screen->SetCurItem( NULL );
376  m_canvas->EndMouseCapture( -1, -1, wxEmptyString, false );
377  m_canvas->Refresh();
378  OnModify();
379 }
380 
381 
382 // A helper function to find any sheet pins at the specified position.
383 static const SCH_SHEET_PIN* getSheetPin( SCH_SCREEN* aScreen, const wxPoint& aPosition )
384 {
385  for( SCH_ITEM* item = aScreen->GetDrawItems(); item; item = item->Next() )
386  {
387  if( item->Type() == SCH_SHEET_T )
388  {
389  SCH_SHEET* sheet = (SCH_SHEET*) item;
390 
391  for( const SCH_SHEET_PIN& pin : sheet->GetPins() )
392  {
393  if( pin.GetPosition() == aPosition )
394  return &pin;
395  }
396  }
397  }
398 
399  return nullptr;
400 }
401 
402 
413 static void ComputeBreakPoint( SCH_SCREEN* aScreen, SCH_LINE* aSegment, wxPoint& aPosition )
414 {
415  wxCHECK_RET( aSegment != nullptr, wxT( "Cannot compute break point of NULL line segment." ) );
416 
417  SCH_LINE* nextSegment = aSegment->Next();
418 
419  wxPoint midPoint;
420  int iDx = aSegment->GetEndPoint().x - aSegment->GetStartPoint().x;
421  int iDy = aSegment->GetEndPoint().y - aSegment->GetStartPoint().y;
422 
423  const SCH_SHEET_PIN* connectedPin = getSheetPin( aScreen, aSegment->GetStartPoint() );
424  auto force = connectedPin ? connectedPin->GetEdge() : SCH_SHEET_PIN::SHEET_UNDEFINED_SIDE;
425 
427  {
428  if( aPosition.x == connectedPin->GetPosition().x ) // push outside sheet boundary
429  {
430  int direction = ( force == SCH_SHEET_PIN::SHEET_LEFT_SIDE ) ? -1 : 1;
431  aPosition.x += aScreen->GetGridSize().x * direction;
432  }
433 
434  midPoint.x = aPosition.x;
435  midPoint.y = aSegment->GetStartPoint().y; // force horizontal
436  }
437  else if( iDy != 0 ) // keep the first segment orientation (vertical)
438  {
439  midPoint.x = aSegment->GetStartPoint().x;
440  midPoint.y = aPosition.y;
441  }
442  else if( iDx != 0 ) // keep the first segment orientation (horizontal)
443  {
444  midPoint.x = aPosition.x;
445  midPoint.y = aSegment->GetStartPoint().y;
446  }
447  else
448  {
449  if( std::abs( aPosition.x - aSegment->GetStartPoint().x ) <
450  std::abs( aPosition.y - aSegment->GetStartPoint().y ) )
451  {
452  midPoint.x = aSegment->GetStartPoint().x;
453  midPoint.y = aPosition.y;
454  }
455  else
456  {
457  midPoint.x = aPosition.x;
458  midPoint.y = aSegment->GetStartPoint().y;
459  }
460  }
461 
462  aSegment->SetEndPoint( midPoint );
463  nextSegment->SetStartPoint( midPoint );
464  nextSegment->SetEndPoint( aPosition );
465 }
466 
467 
469 {
470  SCH_SCREEN* screen = GetScreen();
471 
472  SetRepeatItem( NULL );
473 
474  if( ( screen->GetCurItem() == NULL ) || !screen->GetCurItem()->IsNew() )
475  return;
476 
477  RemoveFromScreen( screen->GetCurItem() );
479  screen->SetCurItem( NULL );
480 }
481 
482 
484 {
485  PICKED_ITEMS_LIST oldItems;
486  oldItems.m_Status = UR_WIRE_IMAGE;
487 
488  SCH_ITEM* item;
489  SCH_ITEM* next_item;
490 
491  for( item = GetScreen()->GetDrawItems(); item; item = next_item )
492  {
493  next_item = item->Next();
494 
495  if( item->Type() == SCH_JUNCTION_T || item->Type() == SCH_LINE_T )
496  {
497  GetScreen()->Remove( item );
498  GetCanvas()->GetView()->Remove( item );
499 
500  oldItems.PushItem( ITEM_PICKER( item, UR_WIRE_IMAGE ) );
501 
502  SCH_ITEM* item_copy = static_cast<SCH_ITEM*>( item->Clone() );
503 
504  GetScreen()->GetDrawList().Insert( item_copy, next_item );
505  GetCanvas()->GetView()->Add( item_copy );
506  }
507  }
508 
509  if( oldItems.GetCount() != 0 )
510  SaveCopyInUndoList( oldItems, UR_WIRE_IMAGE );
511 }
512 
513 
514 bool SCH_EDIT_FRAME::TrimWire( const wxPoint& aStart, const wxPoint& aEnd, bool aAppend )
515 {
516  SCH_LINE* line;
517  SCH_ITEM* next_item = NULL;
518  bool retval = false;
519 
520  if( aStart == aEnd )
521  return retval;
522 
523  for( SCH_ITEM* item = GetScreen()->GetDrawItems(); item; item = next_item )
524  {
525  next_item = item->Next();
526 
527  // Don't remove wires that are already deleted or are currently being dragged
528  if( item->GetFlags() &
530  continue;
531 
532  if( item->Type() != SCH_LINE_T || item->GetLayer() != LAYER_WIRE )
533  continue;
534 
535  line = (SCH_LINE*) item;
536  if( !IsPointOnSegment( line->GetStartPoint(), line->GetEndPoint(), aStart ) ||
537  !IsPointOnSegment( line->GetStartPoint(), line->GetEndPoint(), aEnd ) )
538  continue;
539 
540  // Step 1: break the segment on one end. return_line remains line if not broken.
541  // Ensure that *line points to the segment containing aEnd
542  SCH_LINE* return_line = line;
543  aAppend |= BreakSegment( line, aStart, aAppend, &return_line );
544  if( IsPointOnSegment( return_line->GetStartPoint(), return_line->GetEndPoint(), aEnd ) )
545  line = return_line;
546 
547  // Step 2: break the remaining segment. return_line remains line if not broken.
548  // Ensure that *line _also_ contains aStart. This is our overlapping segment
549  aAppend |= BreakSegment( line, aEnd, aAppend, &return_line );
550  if( IsPointOnSegment( return_line->GetStartPoint(), return_line->GetEndPoint(), aStart ) )
551  line = return_line;
552 
553  SaveCopyInUndoList( (SCH_ITEM*)line, UR_DELETED, aAppend );
554  RemoveFromScreen( (SCH_ITEM*)line );
555  aAppend = true;
556  retval = true;
557  }
558 
559  return retval;
560 }
561 
562 
564 {
565  SCH_ITEM* item = NULL;
566  SCH_ITEM* secondItem = NULL;
567  PICKED_ITEMS_LIST itemList;
568  SCH_SCREEN* screen = GetScreen();
569 
570  auto remove_item = [ &itemList ]( SCH_ITEM* aItem ) -> void
571  {
572  aItem->SetFlags( STRUCT_DELETED );
573  itemList.PushItem( ITEM_PICKER( aItem, UR_DELETED ) );
574  };
575 
576  BreakSegmentsOnJunctions( true );
577 
578  for( item = screen->GetDrawItems(); item; item = item->Next() )
579  {
580  if( ( item->Type() != SCH_LINE_T )
581  && ( item->Type() != SCH_JUNCTION_T )
582  && ( item->Type() != SCH_NO_CONNECT_T ) )
583  continue;
584 
585  if( item->GetFlags() & STRUCT_DELETED )
586  continue;
587 
588  // Remove unneeded junctions
589  if( ( item->Type() == SCH_JUNCTION_T )
590  && ( !screen->IsJunctionNeeded( item->GetPosition() ) ) )
591  {
592  remove_item( item );
593  continue;
594  }
595 
596  // Remove zero-length lines
597  if( item->Type() == SCH_LINE_T
598  && ( (SCH_LINE*) item )->IsNull() )
599  {
600  remove_item( item );
601  continue;
602  }
603 
604  for( secondItem = item->Next(); secondItem; secondItem = secondItem->Next() )
605  {
606  if( item->Type() != secondItem->Type() || ( secondItem->GetFlags() & STRUCT_DELETED ) )
607  continue;
608 
609  // Merge overlapping lines
610  if( item->Type() == SCH_LINE_T )
611  {
612  SCH_LINE* firstLine = (SCH_LINE*) item;
613  SCH_LINE* secondLine = (SCH_LINE*) secondItem;
614  SCH_LINE* line = NULL;
615  bool needed = false;
616 
617  if( !secondLine->IsParallel( firstLine ) )
618  continue;
619 
620  // Remove identical lines
621  if( firstLine->IsEndPoint( secondLine->GetStartPoint() )
622  && firstLine->IsEndPoint( secondLine->GetEndPoint() ) )
623  {
624  remove_item( secondItem );
625  continue;
626  }
627 
628  // If the end points overlap, check if we still need the junction
629  if( secondLine->IsEndPoint( firstLine->GetStartPoint() ) )
630  needed = screen->IsJunctionNeeded( firstLine->GetStartPoint() );
631  else if( secondLine->IsEndPoint( firstLine->GetEndPoint() ) )
632  needed = screen->IsJunctionNeeded( firstLine->GetEndPoint() );
633 
634  if( !needed && ( line = (SCH_LINE*) secondLine->MergeOverlap( firstLine ) ) )
635  {
636  remove_item( item );
637  remove_item( secondItem );
638  itemList.PushItem( ITEM_PICKER( line, UR_NEW ) );
639  AddToScreen( line );
640  break;
641  }
642  }
643  // Remove duplicate junctions and no-connects
644  else if( secondItem->GetPosition() == item->GetPosition() )
645  remove_item( secondItem );
646  }
647  }
648 
649  for( item = screen->GetDrawItems(); item; item = secondItem )
650  {
651  secondItem = item->Next();
652 
653  if( item->GetFlags() & STRUCT_DELETED )
654  RemoveFromScreen( item );
655  }
656 
657  SaveCopyInUndoList( itemList, UR_CHANGED, aAppend );
658 
659  return itemList.GetCount() > 0;
660 }
661 
662 
663 bool SCH_EDIT_FRAME::BreakSegment( SCH_LINE* aSegment, const wxPoint& aPoint, bool aAppend,
664  SCH_LINE** aNewSegment )
665 {
666  if( !IsPointOnSegment( aSegment->GetStartPoint(), aSegment->GetEndPoint(), aPoint )
667  || aSegment->IsEndPoint( aPoint ) )
668  return false;
669 
670  SaveCopyInUndoList( aSegment, UR_CHANGED, aAppend );
671  SCH_LINE* newSegment = new SCH_LINE( *aSegment );
672  SaveCopyInUndoList( newSegment, UR_NEW, true );
673 
674  newSegment->SetStartPoint( aPoint );
675  aSegment->SetEndPoint( aPoint );
676  AddToScreen( newSegment );
677 
678  if( aNewSegment )
679  *aNewSegment = newSegment;
680 
681  return true;
682 }
683 
684 
685 bool SCH_EDIT_FRAME::BreakSegments( const wxPoint& aPoint, bool aAppend )
686 {
687  bool brokenSegments = false;
688 
689  for( SCH_ITEM* segment = GetScreen()->GetDrawItems(); segment; segment = segment->Next() )
690  {
691  if( ( segment->Type() != SCH_LINE_T ) || ( segment->GetLayer() == LAYER_NOTES ) )
692  continue;
693 
694  brokenSegments |= BreakSegment( (SCH_LINE*) segment, aPoint, aAppend || brokenSegments );
695  }
696 
697  return brokenSegments;
698 }
699 
700 
702 {
703  bool brokenSegments = false;
704 
705  for( SCH_ITEM* item = GetScreen()->GetDrawItems(); item; item = item->Next() )
706  {
707  if( item->Type() == SCH_JUNCTION_T )
708  {
709  SCH_JUNCTION* junction = ( SCH_JUNCTION* ) item;
710 
711  if( BreakSegments( junction->GetPosition(), brokenSegments || aAppend ) )
712  brokenSegments = true;
713  }
714  else
715  {
716  SCH_BUS_ENTRY_BASE* busEntry = dynamic_cast<SCH_BUS_ENTRY_BASE*>( item );
717  if( busEntry )
718  {
719  if( BreakSegments( busEntry->GetPosition(), brokenSegments || aAppend )
720  || BreakSegments( busEntry->m_End(), brokenSegments || aAppend ) )
721  brokenSegments = true;
722  }
723  }
724  }
725 
726  return brokenSegments;
727 }
728 
729 
730 void SCH_EDIT_FRAME::DeleteJunction( SCH_ITEM* aJunction, bool aAppend )
731 {
732  SCH_SCREEN* screen = GetScreen();
733  PICKED_ITEMS_LIST itemList;
734 
735  auto remove_item = [ & ]( SCH_ITEM* aItem ) -> void
736  {
737  aItem->SetFlags( STRUCT_DELETED );
738  itemList.PushItem( ITEM_PICKER( aItem, UR_DELETED ) );
739  RemoveFromScreen( aItem );
740  };
741 
742  remove_item( aJunction );
743 
744  for( SCH_ITEM* item = screen->GetDrawItems(); item; item = item->Next() )
745  {
746  SCH_LINE* firstLine = dynamic_cast<SCH_LINE*>( item );
747 
748  if( !firstLine || !firstLine->IsEndPoint( aJunction->GetPosition() )
749  || ( firstLine->GetFlags() & STRUCT_DELETED ) )
750  continue;
751 
752  for( SCH_ITEM* secondItem = item->Next(); secondItem; secondItem = secondItem->Next() )
753  {
754  SCH_LINE* secondLine = dynamic_cast<SCH_LINE*>( secondItem );
755 
756  if( !secondLine || !secondLine->IsEndPoint( aJunction->GetPosition() )
757  || ( secondItem->GetFlags() & STRUCT_DELETED )
758  || !secondLine->IsParallel( firstLine ) )
759  continue;
760 
761 
762  // Remove identical lines
763  if( firstLine->IsEndPoint( secondLine->GetStartPoint() )
764  && firstLine->IsEndPoint( secondLine->GetEndPoint() ) )
765  {
766  remove_item( secondItem );
767  continue;
768  }
769 
770  // Try to merge the remaining lines
771  if( SCH_LINE* line = (SCH_LINE*) secondLine->MergeOverlap( firstLine ) )
772  {
773  remove_item( item );
774  remove_item( secondItem );
775  itemList.PushItem( ITEM_PICKER( line, UR_NEW ) );
776  AddToScreen( line );
777  break;
778  }
779  }
780  }
781 
782  SaveCopyInUndoList( itemList, UR_DELETED, aAppend );
783 
784  SCH_ITEM* nextitem;
785  for( SCH_ITEM* item = screen->GetDrawItems(); item; item = nextitem )
786  {
787  nextitem = item->Next();
788 
789  if( item->GetFlags() & STRUCT_DELETED )
790  RemoveFromScreen( item );
791  }
792 }
793 
794 
795 SCH_JUNCTION* SCH_EDIT_FRAME::AddJunction( const wxPoint& aPosition, bool aAppend )
796 {
797  SCH_JUNCTION* junction = new SCH_JUNCTION( aPosition );
798  SCH_SCREEN* screen = GetScreen();
799  bool broken_segments = false;
800 
801  AddToScreen( junction );
802  broken_segments = BreakSegments( aPosition, aAppend );
804  OnModify();
805  SaveCopyInUndoList( junction, UR_NEW, broken_segments || aAppend );
806 
807  auto view = GetCanvas()->GetView();
808  view->ClearPreview();
809  view->ShowPreview( false );
810  view->ClearHiddenFlags();
811 
812  return junction;
813 }
814 
815 
817 {
818  SCH_NO_CONNECT* no_connect = new SCH_NO_CONNECT( aPosition );
819 
820  SetRepeatItem( no_connect );
821  AddToScreen( no_connect );
824  OnModify();
825 
826  auto view = GetCanvas()->GetView();
827  view->ClearPreview();
828  view->ShowPreview( false );
829  view->ClearHiddenFlags();
830 
831  SaveCopyInUndoList( no_connect, UR_NEW );
832  return no_connect;
833 }
834 
835 
836 /* Abort function for wire, bus or line creation
837  */
838 static void AbortCreateNewLine( EDA_DRAW_PANEL* aPanel, wxDC* aDC )
839 {
840  SCH_SCREEN* screen = (SCH_SCREEN*) aPanel->GetScreen();
841  SCH_EDIT_FRAME* parent = ( SCH_EDIT_FRAME* ) aPanel->GetParent();
842 
843  if( screen->GetCurItem() )
844  {
845  s_wires.DeleteAll(); // Free the list, for a future usage
846  screen->SetCurItem( NULL );
847  }
848  else
849  {
850  parent->SetRepeatItem( NULL );
851  }
852 
853  auto view = static_cast<SCH_DRAW_PANEL*>(aPanel)->GetView();
854  view->ClearPreview();
855  view->ShowPreview( false );
856  view->ClearHiddenFlags();
857 
858  // Clear flags used in edit functions.
859  screen->ClearDrawingState();
860 }
861 
862 
864 {
865  SCH_ITEM* repeater = GetRepeatItem();
866 
867  if( !repeater )
868  return;
869 
870  // clone the repeater, move it, insert into display list, then save a copy
871  // via SetRepeatItem();
872 
873  SCH_ITEM* my_clone = (SCH_ITEM*) repeater->Clone();
874 
875  // If cloning a component then put into 'move' mode.
876  if( my_clone->Type() == SCH_COMPONENT_T )
877  {
878  wxPoint pos = GetCrossHairPosition() - ( (SCH_COMPONENT*) my_clone )->GetPosition();
879 
880  my_clone->SetFlags( IS_NEW );
881  ( (SCH_COMPONENT*) my_clone )->SetTimeStamp( GetNewTimeStamp() );
882  my_clone->Move( pos );
883  PrepareMoveItem( my_clone );
884  }
885  else
886  {
887  my_clone->Move( GetRepeatStep() );
888 
889  if( my_clone->CanIncrementLabel() )
890  ( (SCH_TEXT*) my_clone )->IncrementLabel( GetRepeatDeltaLabel() );
891 
892  AddToScreen( my_clone );
893 
894  if( my_clone->IsConnectable() )
896 
897  SaveCopyInUndoList( my_clone, UR_NEW );
898  my_clone->ClearFlags();
899  }
900 
901  // clone my_clone, now that it has been moved, thus saving new position.
902  SetRepeatItem( my_clone );
903 }
904 
905 
virtual BASE_SCREEN * GetScreen()=0
void GetConnectionPoints(std::vector< wxPoint > &aPoints) const override
Function GetConnectionPoints add all the connection points for this item to aPoints.
Definition: sch_line.cpp:604
Definition of the SCH_SHEET class for Eeschema.
SCH_JUNCTION * AddJunction(const wxPoint &aPosition, bool aPutInUndoList=false)
Add a new junction at aPosition.
KICAD_T Type() const
Function Type()
Definition: base_struct.h:198
void RepeatDrawItem()
Repeat the last item placement if the last item was a bus, bus entry, label, or component.
void DeleteCurrentSegment()
Erase the last segment at the current mouse position.
bool IsPointOnSegment(const wxPoint &aSegStart, const wxPoint &aSegEnd, const wxPoint &aTestPoint)
Function IsPointOnSegment.
Definition: trigo.cpp:39
STATUS_FLAGS GetFlags() const
Definition: base_struct.h:255
virtual bool CanIncrementLabel() const
bool SchematicCleanUp(bool aAppend=false)
Performs routine schematic cleaning including breaking wire and buses and deleting identical objects ...
void BeginSegment(int type)
Creates a new segment ( WIRE, BUS ) or terminates the current segment in progress.
SCH_SHEET_PINS & GetPins()
Definition: sch_sheet.h:334
T * Remove(T *aElement)
Function Remove removes aElement from the list, but does not delete it.
Definition: dlist.h:211
void GetSchematicConnections(std::vector< wxPoint > &aConnections)
Collects a unique list of all possible connection points in the schematic.
SCH_ITEM * GetRepeatItem() const
Return the item which is to be repeated with the insert key.
static void RemoveBacktracks(DLIST< SCH_ITEM > &aWires)
In a contiguous list of wires, remove wires that backtrack over the previous wire.
bool IsNew() const
Definition: base_struct.h:216
bool GetForceHVLines() const
bool IsJunctionNeeded(const wxPoint &aPosition, bool aNew=false)
Test if a junction is required for the items at aPosition on the screen.
Definition: sch_screen.cpp:326
void OnModify()
Must be called after a schematic change in order to set the "modify" flag of the current screen* and ...
virtual EDA_ITEM * Clone() const
Function Clone creates a duplicate of this item with linked list members set to NULL.
const wxPoint GetRepeatStep() const
#define SKIP_STRUCT
flag indicating that the structure should be ignored
Definition: base_struct.h:122
bool IsParallel(SCH_LINE *aLine)
Definition: sch_line.cpp:387
void RemoveFromScreen(SCH_ITEM *aItem)
Remove an item from the screen (and view)
bool BreakSegments(const wxPoint &aPoint, bool aAppend=false)
Checks every wire and bus for a intersection at aPoint and break into two segments at aPoint if an in...
bool BreakSegmentsOnJunctions(bool aApped=false)
Tests all junctions and bus entries in the schematic for intersections with wires and buses and break...
virtual void Remove(VIEW_ITEM *aItem)
Function Remove() Removes a VIEW_ITEM from the view.
Definition: view.cpp:366
static void DrawSegment(EDA_DRAW_PANEL *aPanel, wxDC *aDC, const wxPoint &aPosition, bool aErase)
Mouse capture callback for drawing line segments.
SHEET_SIDE GetEdge() const
virtual void EndMouseCapture(int aId=-1, int aCursorId=-1, const wxString &aTitle=wxEmptyString, bool aCallEndFunc=true)
Function EndMouseCapture ends mouse a capture.
static void ComputeBreakPoint(SCH_SCREEN *aScreen, SCH_LINE *aSegment, wxPoint &new_pos)
Function ComputeBreakPoint computes the middle coordinate for 2 segments from the start point to aPos...
T * begin() const
Definition: dlist.h:218
void PushItem(const ITEM_PICKER &aItem)
Function PushItem pushes aItem to the top of the list.
wxPoint GetEndPoint() const
Definition: sch_line.h:80
Schematic editor (Eeschema) main window.
SCH_LINE * Next() const
Definition: sch_line.h:61
SCH_LAYER_ID GetLayer() const
Function GetLayer returns the layer this item is on.
void Remove(SCH_ITEM *aItem)
Remove aItem from the schematic associated with this screen.
Definition: sch_screen.cpp:176
bool TestDanglingEnds()
Test all of the connectable objects in the schematic for unused connection points.
wxPoint m_End() const
int GetRepeatDeltaLabel() const
EDA_ITEM * Next() const
Definition: base_struct.h:206
void DeleteAll()
Function DeleteAll deletes all items on the list and leaves the list empty.
Definition: dlist.cpp:44
static const SCH_SHEET_PIN * getSheetPin(SCH_SCREEN *aScreen, const wxPoint &aPosition)
void EndSegment()
Terminate a bus, wire, or line creation.
#define abs(a)
Definition: auxiliary.h:84
SCH_ITEM * Next() const
void SetRepeatItem(SCH_ITEM *aItem)
Clone aItem and owns that clone in this container.
void SetEndPoint(const wxPoint &aPosition)
Definition: sch_line.h:82
SCH_ITEM * Back() const
void PushBack(T *aNewElement)
Function PushBack puts aNewElement at the end of the list sequence.
Definition: dlist.h:250
wxPoint GetStartPoint() const
Definition: sch_line.h:76
Base class for a bus or wire entry.
Definition: sch_bus_entry.h:41
#define IS_NEW
New item, just created.
Definition: base_struct.h:111
virtual EDA_DRAW_FRAME * GetParent() const =0
SCH_SCREEN * GetScreen() const override
Function GetScreen returns a pointer to a BASE_SCREEN or one of its derivatives.
#define IS_DRAGGED
Item being dragged.
Definition: base_struct.h:113
#define SELECTED
Definition: base_struct.h:118
timestamp_t GetNewTimeStamp()
Definition: common.cpp:187
virtual wxPoint GetPosition() const =0
Function GetPosition.
Item is being added to the view.
Definition: view_item.h:60
void PrepareMoveItem(SCH_ITEM *aItem)
Start moving aItem using the mouse.
Definition: schedit.cpp:758
void SetFlags(STATUS_FLAGS aMask)
Definition: base_struct.h:253
wxPoint GetPosition() const override
Function GetPosition.
Definition: sch_junction.h:103
T * GetLast() const
Function GetLast returns the last T* in the list without removing it, or NULL if the list is empty...
Definition: dlist.h:170
SCH_ITEM * GetCurItem() const
Return the currently selected SCH_ITEM, overriding BASE_SCREEN::GetCurItem().
Definition: sch_screen.h:196
#define IS_DELETED
Definition: base_struct.h:114
virtual void SetMouseCapture(MOUSE_CAPTURE_CALLBACK aMouseCaptureCallback, END_MOUSE_CAPTURE_CALLBACK aEndMouseCaptureCallback)
Function SetMouseCapture sets the mouse capture and end mouse capture callbacks to aMouseCaptureCallb...
virtual bool IsConnectable() const
Function IsConnectable returns true if the schematic item can connect to another schematic item...
void SetStartPoint(const wxPoint &aPosition)
Definition: sch_line.h:78
SCH_DRAW_PANEL * GetCanvas() const override
void SaveCopyInUndoList(SCH_ITEM *aItemToCopy, UNDO_REDO_T aTypeCommand, bool aAppend=false, const wxPoint &aTransformPoint=wxPoint(0, 0))
Create a copy of the current schematic item, and put it in the undo list.
void ClearPreview()
Definition: sch_view.cpp:105
virtual void CallMouseCapture(wxDC *aDC, const wxPoint &aPosition, bool aErase)
Function CallMouseCapture calls the mouse capture callback.
T * GetFirst() const
Function GetFirst returns the first T* in the list without removing it, or NULL if the list is empty...
Definition: dlist.h:163
#define STRUCT_DELETED
flag indication structures to be erased
Definition: base_struct.h:120
VIEW_GROUP extends VIEW_ITEM by possibility of grouping items into a single object.
Define a sheet pin (label) used in sheets to create hierarchical schematics.
Definition: sch_sheet.h:61
Class PICKED_ITEMS_LIST is a holder to handle information on schematic or board items.
virtual void Update(VIEW_ITEM *aItem, int aUpdateFlags)
For dynamic VIEWs, informs the associated VIEW that the graphical representation of this item has cha...
Definition: view.cpp:1538
KIGFX::SCH_VIEW * GetView() const
bool IsNull() const
Definition: sch_line.h:74
Sheet symbol placed in a schematic, and is the entry point for a sub schematic.
Definition: sch_sheet.h:209
unsigned GetCount() const
Function GetCount.
virtual wxPoint GetPosition() const override
Function GetPosition.
Definition: sch_text.h:194
void AddToScreen(SCH_ITEM *aItem)
Add an item to the screen (and view)
static void AbortCreateNewLine(EDA_DRAW_PANEL *aPanel, wxDC *aDC)
EDA_DRAW_PANEL * m_canvas
The area to draw on.
Definition: draw_frame.h:108
bool IsEndPoint(const wxPoint &aPoint) const
Definition: sch_line.h:69
SCH_ITEM * GetDrawItems() const
Definition: sch_screen.h:160
Definition the SCH_COMPONENT class for Eeschema.
EDA_ITEM * MergeOverlap(SCH_LINE *aLine)
Check line against aLine to see if it overlaps and merge if it does.
Definition: sch_line.cpp:400
Segment description base class to describe items which have 2 end points (track, wire, draw line ...)
Definition: sch_line.h:41
void DeleteJunction(SCH_ITEM *aItem, bool aAppend=false)
Removes a given junction and heals any wire segments under the junction.
void SetCurItem(SCH_ITEM *aItem)
Sets the currently selected object, m_CurrentItem.
Definition: sch_screen.h:204
size_t i
Definition: json11.cpp:597
const wxRealPoint & GetGridSize() const
Return the grid size of the currently selected grid.
Definition: base_screen.h:410
Class SCH_COMPONENT describes a real schematic component.
Definition: sch_component.h:69
Class EDA_ITEM is a base class for most all the KiCad significant classes, used in schematics and boa...
Definition: base_struct.h:151
bool TrimWire(const wxPoint &aStart, const wxPoint &aEnd, bool aAppend=true)
If any single wire passes through both points, remove the portion between the two points...
SCH_LINE * Back() const
Definition: sch_line.h:62
void ClearFlags(STATUS_FLAGS aMask=EDA_ITEM_ALL_FLAGS)
Definition: base_struct.h:254
unsigned GetCount() const
Function GetCount returns the number of elements in the list.
Definition: dlist.h:126
bool BreakSegment(SCH_LINE *aSegment, const wxPoint &aPoint, bool aAppend=false, SCH_LINE **aNewSegment=NULL)
Breaks a single segment into two at the specified point.
virtual void Add(VIEW_ITEM *aItem, int aDrawPriority=-1)
Function Add() Adds a VIEW_ITEM to the view.
Definition: view.cpp:336
void ClearDrawingState()
Clear the state flags of all the items in the screen.
Definition: sch_screen.cpp:562
virtual void Refresh(bool eraseBackground=true, const wxRect *rect=NULL)
DLIST< SCH_ITEM > & GetDrawList()
Definition: sch_screen.h:119
SCH_NO_CONNECT * AddNoConnect(const wxPoint &aPosition)
Add no connect item to the current schematic sheet at aPosition.
wxPoint GetCrossHairPosition(bool aInvertY=false) const
Function GetCrossHairPosition return the current cross hair position in logical (drawing) coordinates...
Class SCH_ITEM is a base class for any item which can be embedded within the SCHEMATIC container clas...
Implementation of the label properties dialog.
virtual void SetMouseCaptureCallback(MOUSE_CAPTURE_CALLBACK aMouseCaptureCallback)
void Insert(T *aNewElement, T *aElementAfterMe)
Function Insert puts aNewElement just in front of aElementAfterMe in the list sequence.
Definition: dlist.h:200
void SaveWireImage()
Save a copy of the current wire image in the undo list.
static DLIST< SCH_ITEM > s_wires
wxPoint GetPosition() const override
Function GetPosition.
#define IS_MOVED
Item being moved.
Definition: base_struct.h:110
virtual void Move(const wxPoint &aMoveVector)=0
Function Move moves the item by aMoveVector to a new position.