KiCad PCB EDA Suite
Loading...
Searching...
No Matches
view.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) 2013-2017 CERN
5 * Copyright The KiCad Developers, see AUTHORS.txt for contributors.
6 *
7 * @author Tomasz Wlostowski <[email protected]>
8 * @author Maciej Suminski <[email protected]>
9 *
10 * This program is free software; you can redistribute it and/or
11 * modify it under the terms of the GNU General Public License
12 * as published by the Free Software Foundation; either version 2
13 * of the License, or (at your option) any later version.
14 *
15 * This program is distributed in the hope that it will be useful,
16 * but WITHOUT ANY WARRANTY; without even the implied warranty of
17 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
18 * GNU General Public License for more details.
19 *
20 * You should have received a copy of the GNU General Public License
21 * along with this program; if not, you may find one here:
22 * http://www.gnu.org/licenses/old-licenses/gpl-2.0.html
23 * or you may search the http://www.gnu.org website for the version 2 license,
24 * or you may write to the Free Software Foundation, Inc.,
25 * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA
26 */
27
28
29#include <layer_ids.h>
30#include <trace_helpers.h>
31#include <wx/log.h>
32
33#include <view/view.h>
34#include <view/view_group.h>
35#include <view/view_item.h>
36#include <view/view_rtree.h>
37#include <view/view_overlay.h>
38
39#include <gal/definitions.h>
41#include <gal/painter.h>
42#include <algorithm>
43
44#include <core/profile.h>
45
46#ifdef KICAD_GAL_PROFILE
47#include <wx/log.h>
48#endif
49
50namespace KIGFX {
51
52class VIEW;
53
55{
56public:
58 m_view( nullptr ),
61 m_drawPriority( 0 ),
62 m_cachedIndex( -1 ),
63 m_groups( nullptr ),
64 m_groupsSize( 0 ) {}
65
67 {
69 }
70
71 int GetFlags() const
72 {
73 return m_flags;
74 }
75
76private:
77 friend class VIEW;
78
85 int getGroup( int aLayer ) const
86 {
87 for( int i = 0; i < m_groupsSize; ++i )
88 {
89 if( m_groups[i].first == aLayer )
90 return m_groups[i].second;
91 }
92
93 return -1;
94 }
95
102 void setGroup( int aLayer, int aGroup )
103 {
104 // Look if there is already an entry for the layer
105 for( int i = 0; i < m_groupsSize; ++i )
106 {
107 if( m_groups[i].first == aLayer )
108 {
109 m_groups[i].second = aGroup;
110 return;
111 }
112 }
113
114 // If there was no entry for the given layer - create one
115 std::pair<int, int>* newGroups = new std::pair<int, int>[m_groupsSize + 1];
116
117 if( m_groupsSize > 0 )
118 {
119 std::copy( m_groups, m_groups + m_groupsSize, newGroups );
120 delete[] m_groups;
121 }
122
123 m_groups = newGroups;
124 newGroups[m_groupsSize++] = { aLayer, aGroup };
125 }
126
127
132 {
133 delete[] m_groups;
134 m_groups = nullptr;
135 m_groupsSize = 0;
136 }
137
143 inline bool storesGroups() const
144 {
145 return m_groupsSize > 0;
146 }
147
155 void reorderGroups( std::unordered_map<int, int> aReorderMap )
156 {
157 for( int i = 0; i < m_groupsSize; ++i )
158 {
159 int orig_layer = m_groups[i].first;
160 int new_layer = orig_layer;
161
162 if( aReorderMap.count( orig_layer ) )
163 new_layer = aReorderMap.at( orig_layer );
164
165 m_groups[i].first = new_layer;
166 }
167 }
168
175 void saveLayers( const std::vector<int>& aLayers )
176 {
177 m_layers.clear();
178
179 for( int layer : aLayers )
180 {
181 wxCHECK2_MSG( layer >= 0 && layer < VIEW::VIEW_MAX_LAYERS, continue,
182 wxString::Format( wxT( "Invalid layer number: %d" ), layer ) );
183 m_layers.push_back( layer );
184 }
185 }
186
190 int requiredUpdate() const
191 {
192 return m_requiredUpdate;
193 }
194
199 {
201 }
202
206 bool isRenderable() const
207 {
208 return m_flags == VISIBLE;
209 }
210
216
217 std::pair<int, int>* m_groups;
220
221 std::vector<int> m_layers;
222
224};
225
226
228{
229 if( aItem->m_viewPrivData )
230 {
231 if( aItem->m_viewPrivData->m_view )
232 aItem->m_viewPrivData->m_view->VIEW::Remove( aItem );
233
234 delete aItem->m_viewPrivData;
235 aItem->m_viewPrivData = nullptr;
236 }
237}
238
239
241 m_enableOrderModifier( true ),
242 m_scale( 4.0 ),
243 m_minScale( 0.2 ), m_maxScale( 50000.0 ),
244 m_mirrorX( false ), m_mirrorY( false ),
245 m_painter( nullptr ),
246 m_gal( nullptr ),
247 m_useDrawPriority( false ),
249 m_reverseDrawOrder( false ),
251{
252 // Set m_boundary to define the max area size. The default area size
253 // is defined here as the max value of a int.
254 // this is a default value acceptable for Pcbnew and Gerbview, but too large for Eeschema.
255 // So in eeschema a call to SetBoundary() with a smaller value will be needed.
256 typedef std::numeric_limits<int> coord_limits;
257 double pos = coord_limits::lowest() / 2 + coord_limits::epsilon();
258 double size = coord_limits::max() - coord_limits::epsilon();
259 m_boundary.SetOrigin( pos, pos );
260 m_boundary.SetSize( size, size );
261
262 m_allItems.reset( new std::vector<VIEW_ITEM*> );
263 m_allItems->reserve( 32768 );
264
265 // Redraw everything at the beginning
266 MarkDirty();
267
268 // View uses layers to display EDA_ITEMs (item may be displayed on several layers, for example
269 // pad may be shown on pad, pad hole and solder paste layers). There are usual copper layers
270 // (eg. F.Cu, B.Cu, internal and so on) and layers for displaying objects such as texts,
271 // silkscreen, pads, vias, etc.
272 for( int ii = 0; ii < VIEW_MAX_LAYERS; ++ii )
273 {
274 auto [it, _] = m_layers.emplace( ii, VIEW_LAYER() );
275 VIEW_LAYER& l = it->second;
276
277 l.items = std::make_shared<VIEW_RTREE>();
278 l.id = ii;
279 l.renderingOrder = ii;
280 l.visible = true;
281 l.displayOnly = false;
282 l.diffLayer = false;
283 l.hasNegatives = false;
285 }
286
288
289 m_preview.reset( new KIGFX::VIEW_GROUP() );
290 Add( m_preview.get() );
291}
292
293
295{
296 Remove( m_preview.get() );
297}
298
299
300void VIEW::Add( VIEW_ITEM* aItem, int aDrawPriority )
301{
302 if( aDrawPriority < 0 )
303 aDrawPriority = m_nextDrawPriority++;
304
305 if( !aItem->m_viewPrivData )
306 aItem->m_viewPrivData = new VIEW_ITEM_DATA;
307
308 wxASSERT_MSG( aItem->m_viewPrivData->m_view == nullptr || aItem->m_viewPrivData->m_view == this,
309 wxS( "Already in a different view!" ) );
310
311 aItem->m_viewPrivData->m_view = this;
312 aItem->m_viewPrivData->m_drawPriority = aDrawPriority;
313 const BOX2I bbox = aItem->ViewBBox();
314 aItem->m_viewPrivData->m_bbox = bbox;
315 aItem->m_viewPrivData->m_cachedIndex = m_allItems->size();
316
317 std::vector<int> layers = aItem->ViewGetLayers();
318
319 std::erase_if( layers, []( int layer )
320 {
321 return layer < 0 || layer >= VIEW_MAX_LAYERS;
322 } );
323
324 if( layers.empty() )
325 return;
326
327 aItem->viewPrivData()->saveLayers( layers );
328
329 m_allItems->push_back( aItem );
330
331 for( int layer : layers )
332 {
333 VIEW_LAYER& l = m_layers[layer];
334 l.items->Insert( aItem, bbox );
336 }
337
338 SetVisible( aItem, true );
339 Update( aItem, KIGFX::INITIAL_ADD );
340}
341
342
344{
345 static int s_gcCounter = 0;
346
347 if( aItem && aItem->m_viewPrivData )
348 {
349 if( aItem->m_viewPrivData->m_view != nullptr && aItem->m_viewPrivData->m_view != this )
350 {
351 wxLogDebug( wxT( "VIEW::Remove: item %s belongs to a different view" ), aItem->GetClass() );
352 return;
353 }
354
355 std::vector<VIEW_ITEM*>::iterator item = m_allItems->end();
356 int cachedIndex = aItem->m_viewPrivData->m_cachedIndex;
357
358 if( cachedIndex >= 0
359 && cachedIndex < static_cast<ssize_t>( m_allItems->size() )
360 && ( *m_allItems )[cachedIndex] == aItem )
361 {
362 item = m_allItems->begin() + cachedIndex;
363 }
364 else
365 {
366 item = std::find( m_allItems->begin(), m_allItems->end(), aItem );
367 }
368
369 if( item != m_allItems->end() )
370 {
371 *item = nullptr;
373
374 s_gcCounter++;
375
376 if( s_gcCounter > 4096 )
377 {
378 // Perform defragmentation
379 std::erase_if( *m_allItems,
380 []( VIEW_ITEM* it )
381 {
382 return it == nullptr;
383 } );
384
385 // Update cached indices
386 for( size_t idx = 0; idx < m_allItems->size(); idx++ )
387 ( *m_allItems )[idx]->m_viewPrivData->m_cachedIndex = idx;
388
389 s_gcCounter = 0;
390 }
391 }
392
393 const BOX2I* bbox = &aItem->m_viewPrivData->m_bbox;
394
395 for( int layer : aItem->m_viewPrivData->m_layers )
396 {
397 VIEW_LAYER& l = m_layers[layer];
398 l.items->Remove( aItem, bbox );
400
401 // Clear the GAL cache
402 int prevGroup = aItem->m_viewPrivData->getGroup( layer );
403
404 if( prevGroup >= 0 )
405 m_gal->DeleteGroup( prevGroup );
406 }
407
409 aItem->m_viewPrivData->m_view = nullptr;
410 }
411}
412
413
414void VIEW::SetRequired( int aLayerId, int aRequiredId, bool aRequired )
415{
416 wxCHECK( (unsigned) aLayerId < m_layers.size(), /*void*/ );
417 wxCHECK( (unsigned) aRequiredId < m_layers.size(), /*void*/ );
418
419 if( aRequired )
420 m_layers[aLayerId].requiredLayers.insert( aRequiredId );
421 else
422 m_layers[aLayerId].requiredLayers.erase( aRequired );
423}
424
425
426int VIEW::Query( const BOX2I& aRect, std::vector<LAYER_ITEM_PAIR>& aResult ) const
427{
428 if( m_orderedLayers.empty() )
429 return 0;
430
431 int layer = UNDEFINED_LAYER;
432 auto visitor =
433 [&]( VIEW_ITEM* item ) -> bool
434 {
435 aResult.push_back( VIEW::LAYER_ITEM_PAIR( item, layer ) );
436 return true;
437 };
438
439 std::vector<VIEW_LAYER*>::const_reverse_iterator i;
440
441 // execute queries in reverse direction, so that items that are on the top of
442 // the rendering stack are returned first.
443 for( i = m_orderedLayers.rbegin(); i != m_orderedLayers.rend(); ++i )
444 {
445 // ignore layers that do not contain actual items (i.e. the selection box, menus, floats)
446 if( ( *i )->displayOnly || !( *i )->visible )
447 continue;
448
449 layer = ( *i )->id;
450 ( *i )->items->Query( aRect, visitor );
451 }
452
453 return aResult.size();
454}
455
456
457void VIEW::Query( const BOX2I& aRect, const std::function<bool( VIEW_ITEM* )>& aFunc ) const
458{
459 if( m_orderedLayers.empty() )
460 return;
461
462 for( const auto& i : m_orderedLayers )
463 {
464 // ignore layers that do not contain actual items (i.e. the selection box, menus, floats)
465 if( i->displayOnly || !i->visible )
466 continue;
467
468 i->items->Query( aRect, aFunc );
469 }
470}
471
472
473VECTOR2D VIEW::ToWorld( const VECTOR2D& aCoord, bool aAbsolute ) const
474{
475 const MATRIX3x3D& matrix = m_gal->GetScreenWorldMatrix();
476
477 if( aAbsolute )
478 return VECTOR2D( matrix * aCoord );
479 else
480 return VECTOR2D( matrix.GetScale().x * aCoord.x, matrix.GetScale().y * aCoord.y );
481}
482
483
484double VIEW::ToWorld( double aSize ) const
485{
486 const MATRIX3x3D& matrix = m_gal->GetScreenWorldMatrix();
487
488 return fabs( matrix.GetScale().x * aSize );
489}
490
491
492VECTOR2D VIEW::ToScreen( const VECTOR2D& aCoord, bool aAbsolute ) const
493{
494 const MATRIX3x3D& matrix = m_gal->GetWorldScreenMatrix();
495
496 if( aAbsolute )
497 return VECTOR2D( matrix * aCoord );
498 else
499 return VECTOR2D( matrix.GetScale().x * aCoord.x, matrix.GetScale().y * aCoord.y );
500}
501
502
503double VIEW::ToScreen( double aSize ) const
504{
505 const MATRIX3x3D& matrix = m_gal->GetWorldScreenMatrix();
506
507 return matrix.GetScale().x * aSize;
508}
509
510
511void VIEW::CopySettings( const VIEW* aOtherView )
512{
513 wxASSERT_MSG( false, wxT( "This is not implemented" ) );
514}
515
516
517void VIEW::SetGAL( GAL* aGal )
518{
519 bool recacheGroups = ( m_gal != nullptr ); // recache groups only if GAL is reassigned
520 m_gal = aGal;
521
522 // clear group numbers, so everything is going to be recached
523 if( recacheGroups )
525
526 // every target has to be refreshed
527 MarkDirty();
528
529 // force the new GAL to display the current viewport.
531 SetScale( m_scale );
533}
534
535
537{
538 BOX2D rect;
539 VECTOR2D screenSize = m_gal->GetScreenPixelSize();
540
541 rect.SetOrigin( ToWorld( VECTOR2D( 0, 0 ) ) );
542 rect.SetEnd( ToWorld( screenSize ) );
543
544 return rect.Normalize();
545}
546
547
548void VIEW::SetViewport( const BOX2D& aViewport )
549{
550 VECTOR2D ssize = ToWorld( m_gal->GetScreenPixelSize(), false );
551
552 wxCHECK( fabs(ssize.x) > 0 && fabs(ssize.y) > 0, /*void*/ );
553
554 VECTOR2D centre = aViewport.Centre();
555 VECTOR2D vsize = aViewport.GetSize();
556 double zoom = 1.0 / std::max( fabs( vsize.x / ssize.x ), fabs( vsize.y / ssize.y ) );
557
558 SetCenter( centre );
559 SetScale( GetScale() * zoom );
560}
561
562
563void VIEW::SetMirror( bool aMirrorX, bool aMirrorY )
564{
565 wxASSERT_MSG( !aMirrorY, _( "Mirroring for Y axis is not supported yet" ) );
566
567 m_mirrorX = aMirrorX;
568 m_mirrorY = aMirrorY;
569 m_gal->SetFlip( aMirrorX, aMirrorY );
570
571 // Redraw everything
572 MarkDirty();
573}
574
575
576void VIEW::SetScale( double aScale, VECTOR2D aAnchor )
577{
578 if( aAnchor == VECTOR2D( 0, 0 ) )
579 aAnchor = m_center;
580
581 VECTOR2D a = ToScreen( aAnchor );
582
583 if( aScale < m_minScale )
585 else if( aScale > m_maxScale )
587 else
588 m_scale = aScale;
589
590 m_gal->SetZoomFactor( m_scale );
591 m_gal->ComputeWorldScreenMatrix();
592
593 VECTOR2D delta = ToWorld( a ) - aAnchor;
594
596
597 // Redraw everything after the viewport has changed
598 MarkDirty();
599}
600
601
602void VIEW::SetCenter( const VECTOR2D& aCenter )
603{
604 m_center = aCenter;
605
606 if( !m_boundary.Contains( aCenter ) )
607 {
608 if( m_center.x < m_boundary.GetLeft() )
609 m_center.x = m_boundary.GetLeft();
610 else if( aCenter.x > m_boundary.GetRight() )
611 m_center.x = m_boundary.GetRight();
612
613 if( m_center.y < m_boundary.GetTop() )
614 m_center.y = m_boundary.GetTop();
615 else if( m_center.y > m_boundary.GetBottom() )
616 m_center.y = m_boundary.GetBottom();
617 }
618
619 m_gal->SetLookAtPoint( m_center );
620 m_gal->ComputeWorldScreenMatrix();
621
622 // Redraw everything after the viewport has changed
623 MarkDirty();
624}
625
626
627void VIEW::SetCenter( const VECTOR2D& aCenter, const std::vector<BOX2D>& obscuringScreenRects )
628{
629 if( obscuringScreenRects.empty() )
630 return SetCenter( aCenter );
631
632 BOX2D screenRect( { 0, 0 }, m_gal->GetScreenPixelSize() );
633 SHAPE_POLY_SET unobscuredPoly( screenRect );
634 VECTOR2D unobscuredCenter = screenRect.Centre();
635
636 for( const BOX2D& obscuringScreenRect : obscuringScreenRects )
637 {
638 SHAPE_POLY_SET obscuringPoly( obscuringScreenRect );
639 unobscuredPoly.BooleanSubtract( obscuringPoly );
640 }
641
642 /*
643 * Perform a step-wise deflate to find the center of the largest unobscured area
644 */
645
646 BOX2I bbox = unobscuredPoly.BBox();
647 int step = std::min( bbox.GetWidth(), bbox.GetHeight() ) / 10;
648
649 if( step < 20 )
650 step = 20;
651
652 while( !unobscuredPoly.IsEmpty() )
653 {
654 unobscuredCenter = unobscuredPoly.BBox().Centre();
656 }
657
658 SetCenter( aCenter - ToWorld( unobscuredCenter - screenRect.Centre(), false ) );
659}
660
661
662void VIEW::SetLayerOrder( int aLayer, int aRenderingOrder, bool aAutoSort )
663{
664 m_layers[aLayer].renderingOrder = aRenderingOrder;
665
666 if( aAutoSort )
668}
669
670
671int VIEW::GetLayerOrder( int aLayer ) const
672{
673 return m_layers.at( aLayer ).renderingOrder;
674}
675
676
677void VIEW::SortLayers( std::vector<int>& aLayers ) const
678{
679 std::sort( aLayers.begin(), aLayers.end(),
680 [this]( int a, int b )
681 {
682 return GetLayerOrder( a ) > GetLayerOrder( b );
683 } );
684}
685
686
687void VIEW::ReorderLayerData( std::unordered_map<int, int> aReorderMap )
688{
689 std::map<int,VIEW_LAYER> new_map;
690
691 for( auto& [_, layer] : m_layers )
692 {
693 auto reorder_it = aReorderMap.find( layer.id );
694
695 // If the layer is not in the reorder map or if it is mapped to itself,
696 // just copy the layer to the new map.
697 if( reorder_it == aReorderMap.end() || reorder_it->second == layer.id )
698 {
699 new_map.emplace( layer.id, layer );
700 continue;
701 }
702
703 auto [new_it,__] = new_map.emplace( reorder_it->second, layer );
704 new_it->second.id = reorder_it->second;
705 }
706
707 // Transfer reordered data (using the copy assignment operator ):
708 m_layers = new_map;
709
711
712 for( VIEW_ITEM* item : *m_allItems )
713 {
714 if( !item )
715 continue;
716
717 VIEW_ITEM_DATA* viewData = item->viewPrivData();
718
719 if( !viewData )
720 continue;
721
722 std::vector<int> layers = item->ViewGetLayers();
723 viewData->saveLayers( layers );
724
725 viewData->reorderGroups( aReorderMap );
726
727 viewData->m_requiredUpdate |= COLOR;
729 }
730
731 UpdateItems();
732}
733
734
736{
737 UPDATE_COLOR_VISITOR( int aLayer, PAINTER* aPainter, GAL* aGal ) :
738 layer( aLayer ),
739 painter( aPainter ),
740 gal( aGal )
741 {
742 }
743
744 bool operator()( VIEW_ITEM* aItem )
745 {
746 // Obtain the color that should be used for coloring the item
747 const COLOR4D color = painter->GetSettings()->GetColor( aItem, layer );
748 int group = aItem->viewPrivData()->getGroup( layer );
749
750 if( group >= 0 )
751 gal->ChangeGroupColor( group, color );
752
753 return true;
754 }
755
756 int layer;
759};
760
761
762void VIEW::UpdateLayerColor( int aLayer )
763{
764 // There is no point in updating non-cached layers
765 if( !IsCached( aLayer ) )
766 return;
767
768 BOX2I r;
769
770 r.SetMaximum();
771
772 if( m_gal->IsVisible() )
773 {
775
776 UPDATE_COLOR_VISITOR visitor( aLayer, m_painter, m_gal );
777 m_layers[aLayer].items->Query( r, visitor );
778 MarkTargetDirty( m_layers[aLayer].target );
779 }
780}
781
782
784{
785 if( m_gal->IsVisible() )
786 {
788
789 for( VIEW_ITEM* item : *m_allItems )
790 {
791 if( !item )
792 continue;
793
794 VIEW_ITEM_DATA* viewData = item->viewPrivData();
795
796 if( !viewData )
797 continue;
798
799 for( int layer : viewData->m_layers )
800 {
801 const COLOR4D color = m_painter->GetSettings()->GetColor( item, layer );
802 int group = viewData->getGroup( layer );
803
804 if( group >= 0 )
805 m_gal->ChangeGroupColor( group, color );
806 }
807 }
808 }
809
810 MarkDirty();
811}
812
813
815{
816 UPDATE_DEPTH_VISITOR( int aLayer, int aDepth, GAL* aGal ) :
817 layer( aLayer ),
818 depth( aDepth ),
819 gal( aGal )
820 {
821 }
822
823 bool operator()( VIEW_ITEM* aItem )
824 {
825 int group = aItem->viewPrivData()->getGroup( layer );
826
827 if( group >= 0 )
828 gal->ChangeGroupDepth( group, depth );
829
830 return true;
831 }
832
835};
836
837
839{
840 if( m_topLayers.size() == 0 )
841 return 0;
842
843 return *m_topLayers.begin();
844}
845
846
847void VIEW::SetTopLayer( int aLayer, bool aEnabled )
848{
849 if( aEnabled )
850 {
851 if( m_topLayers.count( aLayer ) == 1 )
852 return;
853
854 m_topLayers.insert( aLayer );
855
856 // Move the layer closer to front
858 m_layers[aLayer].renderingOrder += TOP_LAYER_MODIFIER;
859 }
860 else
861 {
862 if( m_topLayers.count( aLayer ) == 0 )
863 return;
864
865 m_topLayers.erase( aLayer );
866
867 // Restore the previous rendering order
869 m_layers[aLayer].renderingOrder -= TOP_LAYER_MODIFIER;
870 }
871}
872
873
874void VIEW::EnableTopLayer( bool aEnable )
875{
876 if( aEnable == m_enableOrderModifier )
877 return;
878
879 m_enableOrderModifier = aEnable;
880
881 std::set<unsigned int>::iterator it;
882
883 if( aEnable )
884 {
885 for( it = m_topLayers.begin(); it != m_topLayers.end(); ++it )
886 m_layers[*it].renderingOrder += TOP_LAYER_MODIFIER;
887 }
888 else
889 {
890 for( it = m_topLayers.begin(); it != m_topLayers.end(); ++it )
891 m_layers[*it].renderingOrder -= TOP_LAYER_MODIFIER;
892 }
893
896}
897
898
900{
901 std::set<unsigned int>::iterator it;
902
904 {
905 // Restore the previous rendering order for layers that were marked as top
906 for( it = m_topLayers.begin(); it != m_topLayers.end(); ++it )
907 m_layers[*it].renderingOrder -= TOP_LAYER_MODIFIER;
908 }
909
910 m_topLayers.clear();
911}
912
913
915{
917
918 if( m_gal->IsVisible() )
919 {
921
922 for( VIEW_ITEM* item : *m_allItems )
923 {
924 if( !item )
925 continue;
926
927 VIEW_ITEM_DATA* viewData = item->viewPrivData();
928
929 if( !viewData )
930 continue;
931
932 for( int layer : viewData->m_layers )
933 {
934 int group = viewData->getGroup( layer );
935
936 if( group >= 0 )
937 m_gal->ChangeGroupDepth( group, m_layers[layer].renderingOrder );
938 }
939 }
940 }
941
942 MarkDirty();
943}
944
945
947{
948 DRAW_ITEM_VISITOR( VIEW* aView, int aLayer, bool aUseDrawPriority, bool aReverseDrawOrder ) :
949 view( aView ),
950 layer( aLayer ),
951 useDrawPriority( aUseDrawPriority ),
952 reverseDrawOrder( aReverseDrawOrder ),
953 drawForcedTransparent( false ),
955 {
956 }
957
958 bool operator()( VIEW_ITEM* aItem )
959 {
960 wxCHECK( aItem->viewPrivData(), false );
961
963 {
965 return true;
966 }
967
968 const double itemLOD = aItem->ViewGetLOD( layer, view );
969
970 // Conditions that have to be fulfilled for an item to be drawn
971 bool drawCondition = aItem->viewPrivData()->isRenderable() && itemLOD < view->m_scale;
972
973 if( !drawCondition )
974 return true;
975
976 if( useDrawPriority )
977 drawItems.push_back( aItem );
978 else
979 view->draw( aItem, layer );
980
981 return true;
982 }
983
985 {
986 if( reverseDrawOrder )
987 {
988 std::sort( drawItems.begin(), drawItems.end(),
989 []( VIEW_ITEM* a, VIEW_ITEM* b ) -> bool
990 {
991 return b->viewPrivData()->m_drawPriority
992 < a->viewPrivData()->m_drawPriority;
993 } );
994 }
995 else
996 {
997 std::sort( drawItems.begin(), drawItems.end(),
998 []( VIEW_ITEM* a, VIEW_ITEM* b ) -> bool
999 {
1000 return a->viewPrivData()->m_drawPriority
1001 < b->viewPrivData()->m_drawPriority;
1002 } );
1003 }
1004
1005 for( VIEW_ITEM* item : drawItems )
1006 view->draw( item, layer );
1007 }
1008
1012 std::vector<VIEW_ITEM*> drawItems;
1015};
1016
1017
1018void VIEW::redrawRect( const BOX2I& aRect )
1019{
1020 for( VIEW_LAYER* l : m_orderedLayers )
1021 {
1022 if( l->visible && IsTargetDirty( l->target ) && areRequiredLayersEnabled( l->id ) )
1023 {
1024 DRAW_ITEM_VISITOR drawFunc( this, l->id, m_useDrawPriority, m_reverseDrawOrder );
1025
1026 m_gal->SetTarget( l->target );
1027 m_gal->SetLayerDepth( l->renderingOrder );
1028
1029 // Differential layer also work for the negatives, since both special layer types
1030 // will composite on separate layers (at least in Cairo)
1031 if( l->diffLayer )
1032 m_gal->StartDiffLayer();
1033 else if( l->hasNegatives )
1034 m_gal->StartNegativesLayer();
1035
1036 l->items->Query( aRect, drawFunc );
1037
1038 if( m_useDrawPriority )
1039 drawFunc.deferredDraw();
1040
1041 if( l->diffLayer )
1042 m_gal->EndDiffLayer();
1043 else if( l->hasNegatives )
1044 m_gal->EndNegativesLayer();
1045
1046 if( drawFunc.foundForcedTransparent )
1047 {
1048 drawFunc.drawForcedTransparent = true;
1049
1050 m_gal->SetTarget( TARGET_NONCACHED );
1051 m_gal->EnableDepthTest( true );
1052 m_gal->SetLayerDepth( l->renderingOrder );
1053
1054 l->items->Query( aRect, drawFunc );
1055 }
1056 }
1057 }
1058}
1059
1060
1061void VIEW::draw( VIEW_ITEM* aItem, int aLayer, bool aImmediate )
1062{
1063 VIEW_ITEM_DATA* viewData = aItem->viewPrivData();
1064
1065 if( !viewData )
1066 return;
1067
1068 if( IsCached( aLayer ) && !aImmediate )
1069 {
1070 // Draw using cached information or create one
1071 int group = viewData->getGroup( aLayer );
1072
1073 if( group >= 0 )
1074 m_gal->DrawGroup( group );
1075 else
1076 Update( aItem );
1077 }
1078 else
1079 {
1080 // Immediate mode
1081 if( !m_painter->Draw( aItem, aLayer ) )
1082 aItem->ViewDraw( aLayer, this ); // Alternative drawing method
1083 }
1084}
1085
1086
1087void VIEW::draw( VIEW_ITEM* aItem, bool aImmediate )
1088{
1089 std::vector<int> layers = aItem->ViewGetLayers();
1090
1091 // Sorting is needed for drawing order dependent GALs (like Cairo)
1092 if( !m_gal || !m_gal->IsOpenGlEngine())
1093 SortLayers( layers );
1094
1095 for( int layer : layers )
1096 {
1097 auto it = m_layers.find( layer );
1098
1099 if( it == m_layers.end() )
1100 continue;
1101
1102 if( m_gal )
1103 m_gal->SetLayerDepth( it->second.renderingOrder );
1104
1105 draw( aItem, layer, aImmediate );
1106 }
1107}
1108
1109
1110void VIEW::draw( VIEW_GROUP* aGroup, bool aImmediate )
1111{
1112 for( unsigned int i = 0; i < aGroup->GetSize(); i++ )
1113 draw( aGroup->GetItem(i), aImmediate );
1114}
1115
1116
1118{
1119 RECACHE_ITEM_VISITOR( VIEW* aView, GAL* aGal, int aLayer ) :
1120 view( aView ),
1121 gal( aGal ),
1122 layer( aLayer )
1123 {
1124 }
1125
1126 bool operator()( VIEW_ITEM* aItem )
1127 {
1128 VIEW_ITEM_DATA* viewData = aItem->viewPrivData();
1129
1130 if( !viewData )
1131 return false;
1132
1133 // Remove previously cached group
1134 int group = viewData->getGroup( layer );
1135
1136 if( group >= 0 )
1137 gal->DeleteGroup( group );
1138
1139 viewData->setGroup( layer, -1 );
1140 view->Update( aItem );
1141
1142 return true;
1143 }
1144
1148};
1149
1150
1152{
1153 BOX2I r;
1154 r.SetMaximum();
1155
1156 // Invalidate viewPrivData for all items before clearing. This ensures that items
1157 // which persist outside the view (like selection groups) won't have stale references
1158 // to this view, which could cause issues if they're later removed and re-added.
1159 for( VIEW_ITEM* item : *m_allItems )
1160 {
1161 if( item && item->m_viewPrivData )
1162 item->m_viewPrivData->m_view = nullptr;
1163 }
1164
1165 m_allItems->clear();
1166
1167 for( auto& [_, layer] : m_layers )
1168 layer.items->RemoveAll();
1169
1171
1172 m_gal->ClearCache();
1173}
1174
1175
1177{
1179 {
1180 // TARGET_CACHED and TARGET_NONCACHED have to be redrawn together, as they contain
1181 // layers that rely on each other (eg. netnames are noncached, but tracks - are cached)
1182 m_gal->ClearTarget( TARGET_NONCACHED );
1183 m_gal->ClearTarget( TARGET_CACHED );
1184
1185 MarkDirty();
1186 }
1187
1189 {
1190 m_gal->ClearTarget( TARGET_OVERLAY );
1191 }
1192}
1193
1194
1196{
1197#ifdef KICAD_GAL_PROFILE
1198 PROF_TIMER totalRealTime;
1199#endif /* KICAD_GAL_PROFILE */
1200
1201 VECTOR2D screenSize = m_gal->GetScreenPixelSize();
1202 BOX2D rect( ToWorld( VECTOR2D( 0, 0 ) ),
1203 ToWorld( screenSize ) - ToWorld( VECTOR2D( 0, 0 ) ) );
1204
1205 rect.Normalize();
1206 BOX2I recti = BOX2ISafe( rect );
1207
1208 redrawRect( recti );
1209
1210 // All targets were redrawn, so nothing is dirty
1211 MarkClean();
1212
1213#ifdef KICAD_GAL_PROFILE
1214 totalRealTime.Stop();
1215 wxLogTrace( traceGalProfile, wxS( "VIEW::Redraw(): %.1f ms" ), totalRealTime.msecs() );
1216#endif /* KICAD_GAL_PROFILE */
1217}
1218
1219
1221{
1222 return m_gal->GetScreenPixelSize();
1223}
1224
1225
1227{
1229 view( aView )
1230 {
1231 }
1232
1233 bool operator()( VIEW_ITEM* aItem )
1234 {
1235 aItem->viewPrivData()->deleteGroups();
1236
1237 return true;
1238 }
1239
1241};
1242
1243
1245{
1246 BOX2I r;
1247
1248 r.SetMaximum();
1249 CLEAR_LAYER_CACHE_VISITOR visitor( this );
1250
1251 for( auto& [_, layer] : m_layers )
1252 layer.items->Query( r, visitor );
1253}
1254
1255
1256void VIEW::invalidateItem( VIEW_ITEM* aItem, int aUpdateFlags )
1257{
1258 if( aUpdateFlags & INITIAL_ADD )
1259 {
1260 // Don't update layers or bbox, since it was done in VIEW::Add()
1261 // Now that we have initialized, set flags to ALL for the code below
1262 aUpdateFlags = ALL;
1263 }
1264 else
1265 {
1266 // updateLayers updates geometry too, so we do not have to update both of them at the
1267 // same time
1268 if( aUpdateFlags & LAYERS )
1269 updateLayers( aItem );
1270 else if( aUpdateFlags & GEOMETRY )
1271 updateBbox( aItem );
1272 }
1273
1274 std::vector<int> layers = aItem->ViewGetLayers();
1275
1276 // Iterate through layers used by the item and recache it immediately
1277 for( int layer : layers )
1278 {
1279 if( IsCached( layer ) )
1280 {
1281 if( aUpdateFlags & ( GEOMETRY | LAYERS | REPAINT ) )
1282 updateItemGeometry( aItem, layer );
1283 else if( aUpdateFlags & COLOR )
1284 updateItemColor( aItem, layer );
1285 }
1286
1287 // Mark those layers as dirty, so the VIEW will be refreshed
1288 MarkTargetDirty( m_layers[layer].target );
1289 }
1290
1291 aItem->viewPrivData()->clearUpdateFlags();
1292}
1293
1294
1296{
1297 int n = 0;
1298
1299 m_orderedLayers.resize( m_layers.size() );
1300
1301 for( auto& [layer_id, layer] : m_layers )
1302 m_orderedLayers[n++] = &layer;
1303
1305
1306 MarkDirty();
1307}
1308
1309
1310void VIEW::updateItemColor( VIEW_ITEM* aItem, int aLayer )
1311{
1312 VIEW_ITEM_DATA* viewData = aItem->viewPrivData();
1313 wxCHECK( IsCached( aLayer ), /*void*/ ); // This will check if the layer exists
1314
1315 if( !viewData )
1316 return;
1317
1318 // Obtain the color that should be used for coloring the item on the specific layerId
1319 const COLOR4D color = m_painter->GetSettings()->GetColor( aItem, aLayer );
1320 int group = viewData->getGroup( aLayer );
1321
1322 // Change the color, only if it has group assigned
1323 if( group >= 0 )
1324 m_gal->ChangeGroupColor( group, color );
1325}
1326
1327
1328void VIEW::updateItemGeometry( VIEW_ITEM* aItem, int aLayer )
1329{
1330 VIEW_ITEM_DATA* viewData = aItem->viewPrivData();
1331
1332 if( !viewData )
1333 return;
1334
1335 auto it = m_layers.find( aLayer );
1336
1337 if( it == m_layers.end() )
1338 return;
1339
1340 VIEW_LAYER& l = it->second;
1341
1342 // Save the extra map lookup in IsCached by open coding here
1343 if( l.target != TARGET_CACHED )
1344 return;
1345
1346 m_gal->SetTarget( l.target );
1347 m_gal->SetLayerDepth( l.renderingOrder );
1348
1349 // Redraw the item from scratch
1350 int group = viewData->getGroup( aLayer );
1351
1352 if( group >= 0 )
1353 m_gal->DeleteGroup( group );
1354
1355 group = m_gal->BeginGroup();
1356 viewData->setGroup( aLayer, group );
1357
1358 if( !m_painter->Draw( aItem, aLayer ) )
1359 aItem->ViewDraw( aLayer, this ); // Alternative drawing method
1360
1361 m_gal->EndGroup();
1362}
1363
1364
1366{
1367 std::vector<int> layers = aItem->ViewGetLayers();
1368
1369 wxASSERT( aItem->m_viewPrivData ); //must have a viewPrivData
1370
1371 const BOX2I new_bbox = aItem->ViewBBox();
1372 const BOX2I* old_bbox = &aItem->m_viewPrivData->m_bbox;
1373 aItem->m_viewPrivData->m_bbox = new_bbox;
1374
1375 for( int layer : layers )
1376 {
1377 auto it = m_layers.find( layer );
1378
1379 if( it == m_layers.end() )
1380 continue;
1381
1382 VIEW_LAYER& l = it->second;
1383 l.items->Remove( aItem, old_bbox );
1384 l.items->Insert( aItem, new_bbox );
1386 }
1387}
1388
1389
1391{
1392 VIEW_ITEM_DATA* viewData = aItem->viewPrivData();
1393
1394 if( !viewData )
1395 return;
1396
1397 // Remove the item from previous layer set
1398 const BOX2I* old_bbox = &aItem->m_viewPrivData->m_bbox;
1399
1400 for( int layer : aItem->m_viewPrivData->m_layers )
1401 {
1402 auto it = m_layers.find( layer );
1403
1404 if( it == m_layers.end() )
1405 continue;
1406
1407 VIEW_LAYER& l = it->second;
1408 l.items->Remove( aItem, old_bbox );
1410
1411 if( IsCached( l.id ) )
1412 {
1413 // Redraw the item from scratch
1414 int prevGroup = viewData->getGroup( layer );
1415
1416 if( prevGroup >= 0 )
1417 {
1418 m_gal->DeleteGroup( prevGroup );
1419 viewData->setGroup( l.id, -1 );
1420 }
1421 }
1422 }
1423
1424 const BOX2I new_bbox = aItem->ViewBBox();
1425 aItem->m_viewPrivData->m_bbox = new_bbox;
1426
1427 // Add the item to new layer set
1428 std::vector<int> layers = aItem->ViewGetLayers();
1429 viewData->saveLayers( layers );
1430
1431 for( int layer : layers )
1432 {
1433 auto it = m_layers.find( layer );
1434
1435 if( it == m_layers.end() )
1436 continue;
1437
1438 VIEW_LAYER& l = it->second;
1439 l.items->Insert( aItem, new_bbox );
1441 }
1442}
1443
1444
1445bool VIEW::areRequiredLayersEnabled( int aLayerId ) const
1446{
1447 auto it = m_layers.find( aLayerId );
1448
1449 if( it == m_layers.end() )
1450 return false;
1451
1452 for( int layer : it->second.requiredLayers )
1453 {
1454 // That is enough if just one layer is not enabled
1455
1456 auto it2 = m_layers.find( layer );
1457
1458 if( it2 == m_layers.end() || !it2->second.visible )
1459 return false;
1460
1461 if( !areRequiredLayersEnabled( layer ) )
1462 return false;
1463 }
1464
1465 return true;
1466}
1467
1468
1470{
1471 BOX2I r;
1472
1473 r.SetMaximum();
1474
1475 for( const auto& [_, l] : m_layers )
1476 {
1477 if( IsCached( l.id ) )
1478 {
1479 RECACHE_ITEM_VISITOR visitor( this, m_gal, l.id );
1480 l.items->Query( r, visitor );
1481 }
1482 }
1483}
1484
1485
1487{
1488 if( !m_gal->IsVisible() || !m_gal->IsInitialized() )
1489 return;
1490
1492 return;
1493
1494 unsigned int cntGeomUpdate = 0;
1495 bool anyUpdated = false;
1496
1497 for( VIEW_ITEM* item : *m_allItems )
1498 {
1499 if( !item )
1500 continue;
1501
1502 auto vpd = item->viewPrivData();
1503
1504 if( !vpd )
1505 continue;
1506
1507 if( vpd->m_requiredUpdate != NONE )
1508 {
1509 anyUpdated = true;
1510
1511 if( vpd->m_requiredUpdate & ( GEOMETRY | LAYERS ) )
1512 {
1513 cntGeomUpdate++;
1514 }
1515 }
1516 }
1517
1518 unsigned int cntTotal = m_allItems->size();
1519
1520 double ratio = (double) cntGeomUpdate / (double) cntTotal;
1521
1522 // Optimization to improve view update time. If a lot of items (say, 30%) have their
1523 // bboxes/geometry changed it's way faster (around 10 times) to rebuild the R-Trees
1524 // from scratch rather than update the bbox of each changed item. Pcbnew does multiple
1525 // full geometry updates during file load, this can save a solid 30 seconds on load time
1526 // for larger designs...
1527
1528 if( ratio > 0.3 )
1529 {
1530 auto allItems = *m_allItems;
1531
1532 // kill all Rtrees
1533 for( auto& [_, layer] : m_layers )
1534 layer.items->RemoveAll();
1535
1536 // and re-insert items from scratch
1537 for( VIEW_ITEM* item : allItems )
1538 {
1539 if( !item )
1540 continue;
1541
1542 const BOX2I bbox = item->ViewBBox();
1543 item->m_viewPrivData->m_bbox = bbox;
1544
1545 std::vector<int> layers = item->ViewGetLayers();
1546 item->viewPrivData()->saveLayers( layers );
1547
1548 for( int layer : layers )
1549 {
1550 auto it = m_layers.find( layer );
1551
1552 wxCHECK2_MSG( it != m_layers.end(), continue, wxS( "Invalid layer" ) );
1553
1554 VIEW_LAYER& l = it->second;
1555 l.items->Insert( item, bbox );
1557 }
1558
1559 item->viewPrivData()->m_requiredUpdate &= ~( LAYERS | GEOMETRY );
1560 }
1561 }
1562
1563 if( anyUpdated )
1564 {
1566
1567 for( VIEW_ITEM* item : *m_allItems.get() )
1568 {
1569 if( item && item->viewPrivData() && item->viewPrivData()->m_requiredUpdate != NONE )
1570 {
1571 invalidateItem( item, item->viewPrivData()->m_requiredUpdate );
1572 item->viewPrivData()->m_requiredUpdate = NONE;
1573 }
1574 }
1575 }
1576
1577 KI_TRACE( traceGalProfile, wxS( "View update: total items %u, geom %u anyUpdated %u\n" ),
1578 cntTotal, cntGeomUpdate, (unsigned) anyUpdated );
1579
1581}
1582
1583
1584void VIEW::UpdateAllItems( int aUpdateFlags )
1585{
1586 if( aUpdateFlags == NONE )
1587 return;
1588
1589 for( VIEW_ITEM* item : *m_allItems )
1590 {
1591 if( item && item->viewPrivData() )
1592 {
1593 item->viewPrivData()->m_requiredUpdate |= aUpdateFlags;
1595 }
1596 }
1597}
1598
1599
1601 std::function<bool( VIEW_ITEM* )> aCondition )
1602{
1603 if( aUpdateFlags == NONE )
1604 return;
1605
1606 for( VIEW_ITEM* item : *m_allItems )
1607 {
1608 if( !item )
1609 continue;
1610
1611 if( aCondition( item ) )
1612 {
1613 if( item->viewPrivData() )
1614 {
1615 item->viewPrivData()->m_requiredUpdate |= aUpdateFlags;
1617 }
1618 }
1619 }
1620}
1621
1622
1623void VIEW::UpdateAllItemsConditionally( std::function<int( VIEW_ITEM* )> aItemFlagsProvider )
1624{
1625 for( VIEW_ITEM* item : *m_allItems )
1626 {
1627 if( !item )
1628 continue;
1629
1630 if( item->viewPrivData() )
1631 {
1632 int flags = aItemFlagsProvider( item );
1633 item->viewPrivData()->m_requiredUpdate |= flags;
1634
1635 if( flags != NONE )
1637 }
1638 }
1639}
1640
1641
1642
1643std::unique_ptr<VIEW> VIEW::DataReference() const
1644{
1645 std::unique_ptr<VIEW> ret = std::make_unique<VIEW>();
1646 ret->m_allItems = m_allItems;
1647 ret->m_layers = m_layers;
1648 ret->m_hasPendingItemUpdates = m_hasPendingItemUpdates;
1649 ret->SortOrderedLayers();
1650 return ret;
1651}
1652
1653
1654void VIEW::SetVisible( VIEW_ITEM* aItem, bool aIsVisible )
1655{
1656 VIEW_ITEM_DATA* viewData = aItem->viewPrivData();
1657
1658 if( !viewData )
1659 return;
1660
1661 bool cur_visible = viewData->m_flags & VISIBLE;
1662
1663 if( cur_visible != aIsVisible )
1664 {
1665 if( aIsVisible )
1666 viewData->m_flags |= VISIBLE;
1667 else
1668 viewData->m_flags &= ~VISIBLE;
1669
1670 Update( aItem, APPEARANCE | COLOR );
1671 }
1672}
1673
1674
1675void VIEW::Hide( VIEW_ITEM* aItem, bool aHide, bool aHideOverlay )
1676{
1677 VIEW_ITEM_DATA* viewData = aItem->viewPrivData();
1678
1679 if( !viewData )
1680 return;
1681
1682 if( !( viewData->m_flags & VISIBLE ) )
1683 return;
1684
1685 if( aHideOverlay )
1686 viewData->m_flags |= OVERLAY_HIDDEN;
1687
1688 if( aHide )
1689 viewData->m_flags |= HIDDEN;
1690 else
1691 viewData->m_flags &= ~( HIDDEN | OVERLAY_HIDDEN );
1692
1693 Update( aItem, APPEARANCE );
1694}
1695
1696
1697bool VIEW::IsVisible( const VIEW_ITEM* aItem ) const
1698{
1699 const VIEW_ITEM_DATA* viewData = aItem->viewPrivData();
1700
1701 return viewData && ( viewData->m_flags & VISIBLE );
1702}
1703
1704
1705bool VIEW::IsHiddenOnOverlay( const VIEW_ITEM* aItem ) const
1706{
1707 const VIEW_ITEM_DATA* viewData = aItem->viewPrivData();
1708
1709 return viewData && ( viewData->m_flags & OVERLAY_HIDDEN );
1710}
1711
1712
1713bool VIEW::HasItem( const VIEW_ITEM* aItem ) const
1714{
1715 const VIEW_ITEM_DATA* viewData = aItem->viewPrivData();
1716
1717 return viewData && viewData->m_view == this;
1718}
1719
1720
1721void VIEW::Update( const VIEW_ITEM* aItem ) const
1722{
1723 Update( aItem, ALL );
1724}
1725
1726
1727void VIEW::Update( const VIEW_ITEM* aItem, int aUpdateFlags ) const
1728{
1729 VIEW_ITEM_DATA* viewData = aItem->viewPrivData();
1730
1731 if( !viewData )
1732 return;
1733
1734 assert( aUpdateFlags != NONE );
1735
1736 viewData->m_requiredUpdate |= aUpdateFlags;
1738}
1739
1740
1741std::shared_ptr<VIEW_OVERLAY> VIEW::MakeOverlay()
1742{
1743 std::shared_ptr<VIEW_OVERLAY> overlay = std::make_shared<VIEW_OVERLAY>();
1744
1745 Add( overlay.get() );
1746 return overlay;
1747}
1748
1749
1751{
1752 if( !m_preview )
1753 return;
1754
1755 m_preview->Clear();
1756
1757 for( VIEW_ITEM* item : m_ownedItems )
1758 delete item;
1759
1760 m_ownedItems.clear();
1761 Update( m_preview.get() );
1762}
1763
1764
1766{
1767 m_preview.reset( new KIGFX::VIEW_GROUP() );
1768 Add( m_preview.get() );
1769}
1770
1771
1772void VIEW::AddToPreview( VIEW_ITEM* aItem, bool aTakeOwnership )
1773{
1774 Hide( aItem, false );
1775 m_preview->Add( aItem );
1776
1777 if( aTakeOwnership )
1778 m_ownedItems.push_back( aItem );
1779
1780 SetVisible( m_preview.get(), true );
1781 Hide( m_preview.get(), false );
1782 Update( m_preview.get() );
1783}
1784
1785
1786void VIEW::ShowPreview( bool aShow )
1787{
1788 SetVisible( m_preview.get(), aShow );
1789}
1790
1791
1792} // namespace KIGFX
constexpr int ARC_LOW_DEF
Definition base_units.h:128
constexpr BOX2I BOX2ISafe(const BOX2D &aInput)
Definition box2.h:929
BOX2< VECTOR2I > BOX2I
Definition box2.h:922
BOX2< VECTOR2D > BOX2D
Definition box2.h:923
constexpr void SetMaximum()
Definition box2.h:80
constexpr void SetOrigin(const Vec &pos)
Definition box2.h:237
constexpr BOX2< Vec > & Normalize()
Ensure that the height and width are positive.
Definition box2.h:146
constexpr size_type GetWidth() const
Definition box2.h:214
constexpr Vec Centre() const
Definition box2.h:97
constexpr size_type GetHeight() const
Definition box2.h:215
constexpr const SizeVec & GetSize() const
Definition box2.h:206
constexpr void SetEnd(coord_type x, coord_type y)
Definition box2.h:297
A color representation with 4 components: red, green, blue, alpha.
Definition color4d.h:105
Abstract interface for drawing on a 2D-surface.
Contains all the knowledge about how to draw graphical object onto any particular output device.
Definition painter.h:59
Extend VIEW_ITEM by possibility of grouping items into a single object.
Definition view_group.h:43
virtual unsigned int GetSize() const
Return the number of stored items.
virtual VIEW_ITEM * GetItem(unsigned int aIdx) const
bool storesGroups() const
Return information if the item uses at least one group id (ie.
Definition view.cpp:143
std::vector< int > m_layers
Definition view.cpp:221
int requiredUpdate() const
Return current update flag for an item.
Definition view.cpp:190
int m_requiredUpdate
Flag required for updating.
Definition view.cpp:213
int m_flags
Visibility flags.
Definition view.cpp:212
void reorderGroups(std::unordered_map< int, int > aReorderMap)
Reorder the stored groups (to facilitate reordering of layers).
Definition view.cpp:155
int m_cachedIndex
Cached index in m_allItems.
Definition view.cpp:215
void deleteGroups()
Remove all of the stored group ids.
Definition view.cpp:131
bool isRenderable() const
Return if the item should be drawn or not.
Definition view.cpp:206
int m_drawPriority
Order to draw this item in a layer, lowest first.
Definition view.cpp:214
friend class VIEW
Definition view.cpp:77
VIEW * m_view
Current dynamic view the item is assigned to.
Definition view.cpp:211
std::pair< int, int > * m_groups
layer_number:group_id pairs for each layer the item occupies.
Definition view.cpp:217
int getGroup(int aLayer) const
Return number of the group id for the given layer, or -1 in case it was not cached before.
Definition view.cpp:85
BOX2I m_bbox
Stores layer numbers used by the item.
Definition view.cpp:223
void setGroup(int aLayer, int aGroup)
Set a group id for the item and the layer combination.
Definition view.cpp:102
void saveLayers(const std::vector< int > &aLayers)
Save layers used by the item.
Definition view.cpp:175
int GetFlags() const
Definition view.cpp:71
void clearUpdateFlags()
Mark an item as already updated, so it is not going to be redrawn.
Definition view.cpp:198
virtual const BOX2I ViewBBox() const =0
Return the bounding box of the item covering all its layers.
double m_forcedTransparency
Additional transparency for diff'ing items.
Definition view_item.h:210
VIEW_ITEM_DATA * viewPrivData() const
Definition view_item.h:161
virtual void ViewDraw(int aLayer, VIEW *aView) const
Draw the parts of the object belonging to layer aLayer.
Definition view_item.h:127
virtual std::vector< int > ViewGetLayers() const =0
Return the all the layers within the VIEW the object is painted on.
virtual wxString GetClass() const =0
Return the class name.
virtual double ViewGetLOD(int aLayer, const VIEW *aView) const
Return the level of detail (LOD) of the item.
Definition view_item.h:155
VIEW_ITEM_DATA * m_viewPrivData
Definition view_item.h:209
Hold a (potentially large) number of VIEW_ITEMs and renders them on a graphics device provided by the...
Definition view.h:67
double GetScale() const
Definition view.h:277
void SetMirror(bool aMirrorX, bool aMirrorY)
Control the mirroring of the VIEW.
Definition view.cpp:563
void ShowPreview(bool aShow=true)
Definition view.cpp:1786
double m_maxScale
Definition view.h:896
BOX2D GetViewport() const
Return the current viewport visible area rectangle.
Definition view.cpp:536
void CopySettings(const VIEW *aOtherView)
Copy layers and visibility settings from another view.
Definition view.cpp:511
virtual void SetScale(double aScale, VECTOR2D aAnchor={ 0, 0 })
Set the scaling factor, zooming around a given anchor point.
Definition view.cpp:576
static constexpr int TOP_LAYER_MODIFIER
Rendering order modifier for layers that are marked as top layers.
Definition view.h:765
void draw(VIEW_ITEM *aItem, int aLayer, bool aImmediate=false)
Draw an item, but on a specified layers.
Definition view.cpp:1061
bool m_reverseDrawOrder
Flag to reverse the draw order when using draw priority.
Definition view.h:917
void UpdateAllLayersOrder()
Do everything that is needed to apply the rendering order of layers.
Definition view.cpp:914
void updateItemColor(VIEW_ITEM *aItem, int aLayer)
Update colors that are used for an item to be drawn.
Definition view.cpp:1310
void SetViewport(const BOX2D &aViewport)
Set the visible area of the VIEW.
Definition view.cpp:548
void SetRequired(int aLayerId, int aRequiredId, bool aRequired=true)
Mark the aRequiredId layer as required for the aLayerId layer.
Definition view.cpp:414
VECTOR2D ToScreen(const VECTOR2D &aCoord, bool aAbsolute=true) const
Convert a world space point/vector to a point/vector in screen space coordinates.
Definition view.cpp:492
static bool compareRenderingOrder(VIEW_LAYER *aI, VIEW_LAYER *aJ)
Determine rendering order of layers. Used in display order sorting function.
Definition view.h:857
int GetLayerOrder(int aLayer) const
Return rendering order of a particular layer.
Definition view.cpp:671
virtual void Add(VIEW_ITEM *aItem, int aDrawPriority=-1)
Add a VIEW_ITEM to the view.
Definition view.cpp:300
virtual void Remove(VIEW_ITEM *aItem)
Remove a VIEW_ITEM from the view.
Definition view.cpp:343
void ClearTargets()
Clear targets that are marked as dirty.
Definition view.cpp:1176
virtual void EnableTopLayer(bool aEnable)
Enable or disable display of the top layer.
Definition view.cpp:874
bool m_mirrorX
Definition view.h:898
void UpdateAllLayersColor()
Apply the new coloring scheme to all layers.
Definition view.cpp:783
bool m_mirrorY
Definition view.h:899
std::shared_ptr< std::vector< VIEW_ITEM * > > m_allItems
Flat list of all items.
Definition view.h:885
std::shared_ptr< VIEW_OVERLAY > MakeOverlay()
Definition view.cpp:1741
void SetGAL(GAL *aGal)
Assign a rendering device for the VIEW.
Definition view.cpp:517
int Query(const BOX2I &aRect, std::vector< LAYER_ITEM_PAIR > &aResult) const
Find all visible items that touch or are within the rectangle aRect.
Definition view.cpp:426
std::vector< VIEW_ITEM * > m_ownedItems
Definition view.h:873
virtual void Update(const VIEW_ITEM *aItem, int aUpdateFlags) const
For dynamic VIEWs, inform the associated VIEW that the graphical representation of this item has chan...
Definition view.cpp:1727
void invalidateItem(VIEW_ITEM *aItem, int aUpdateFlags)
Manage dirty flags & redraw queuing when updating an item.
Definition view.cpp:1256
const VECTOR2I & GetScreenPixelSize() const
Return the size of the our rendering area in pixels.
Definition view.cpp:1220
bool HasItem(const VIEW_ITEM *aItem) const
Indicates whether or not the given item has been added to the view.
Definition view.cpp:1713
virtual int GetTopLayer() const
Definition view.cpp:838
PAINTER * m_painter
PAINTER contains information how do draw items.
Definition view.h:902
virtual void Redraw()
Immediately redraws the whole view.
Definition view.cpp:1195
void Clear()
Remove all items from the view.
Definition view.cpp:1151
std::set< unsigned int > m_topLayers
The set of layers that are displayed on the top.
Definition view.h:888
bool m_enableOrderModifier
Whether to use rendering order modifier or not.
Definition view.h:876
VECTOR2D ToWorld(const VECTOR2D &aCoord, bool aAbsolute=true) const
Converts a screen space point/vector to a point/vector in world space coordinates.
Definition view.cpp:473
bool IsHiddenOnOverlay(const VIEW_ITEM *aItem) const
Definition view.cpp:1705
void ClearTopLayers()
Remove all layers from the on-the-top set (they are no longer displayed over the rest of layers).
Definition view.cpp:899
void InitPreview()
Definition view.cpp:1765
void SetLayerOrder(int aLayer, int aRenderingOrder, bool aAutoSort=true)
Set rendering order of a particular layer.
Definition view.cpp:662
void ClearPreview()
Definition view.cpp:1750
void MarkClean()
Force redraw of view on the next rendering.
Definition view.h:677
void updateItemGeometry(VIEW_ITEM *aItem, int aLayer)
Update all information needed to draw an item.
Definition view.cpp:1328
static constexpr int VIEW_MAX_LAYERS
Maximum number of layers that may be shown.
Definition view.h:762
double m_minScale
Definition view.h:895
double m_scale
Definition view.h:893
void updateLayers(VIEW_ITEM *aItem)
Update set of layers that an item occupies.
Definition view.cpp:1390
void RecacheAllItems()
Rebuild GAL display lists.
Definition view.cpp:1469
bool areRequiredLayersEnabled(int aLayerId) const
Check if every layer required by the aLayerId layer is enabled.
Definition view.cpp:1445
bool IsTargetDirty(int aTarget) const
Return true if any of layers belonging to the target or the target itself should be redrawn.
Definition view.h:637
int m_nextDrawPriority
The next sequential drawing priority.
Definition view.h:914
bool m_useDrawPriority
Flag to respect draw priority when drawing items.
Definition view.h:911
void UpdateItems()
Iterate through the list of items that asked for updating and updates them.
Definition view.cpp:1486
bool IsCached(int aLayer) const
Return true if the layer is cached.
Definition view.h:655
std::pair< VIEW_ITEM *, int > LAYER_ITEM_PAIR
Definition view.h:71
void SortLayers(std::vector< int > &aLayers) const
Change the order of given layer ids, so after sorting the order corresponds to layers rendering order...
Definition view.cpp:677
void UpdateAllItems(int aUpdateFlags)
Update all items in the view according to the given flags.
Definition view.cpp:1584
bool m_hasPendingItemUpdates
True when at least one item has deferred update flags that still need processing.
Definition view.h:920
std::unique_ptr< KIGFX::VIEW_GROUP > m_preview
Definition view.h:872
static void OnDestroy(VIEW_ITEM *aItem)
Nasty hack, invoked by the destructor of VIEW_ITEM to auto-remove the item from the owning VIEW if th...
Definition view.cpp:227
virtual ~VIEW()
Definition view.cpp:294
GAL * m_gal
Interface to PAINTER that is used to draw items.
Definition view.h:905
std::map< int, VIEW_LAYER > m_layers
The set of possible displayed layers and its properties.
Definition view.h:879
std::unique_ptr< VIEW > DataReference() const
Return a new VIEW object that shares the same set of VIEW_ITEMs and LAYERs.
Definition view.cpp:1643
void Hide(VIEW_ITEM *aItem, bool aHide=true, bool aHideOverlay=false)
Temporarily hide the item in the view (e.g.
Definition view.cpp:1675
virtual void SetTopLayer(int aLayer, bool aEnabled=true)
Set given layer to be displayed on the top or sets back the default order of layers.
Definition view.cpp:847
void AddToPreview(VIEW_ITEM *aItem, bool aTakeOwnership=true)
Definition view.cpp:1772
void UpdateLayerColor(int aLayer)
Apply the new coloring scheme held by RENDER_SETTINGS in case that it has changed.
Definition view.cpp:762
void MarkDirty()
Force redraw of view on the next rendering.
Definition view.h:668
friend class VIEW_ITEM
Definition view.h:69
BOX2D m_boundary
Definition view.h:894
void SetCenter(const VECTOR2D &aCenter)
Set the center point of the VIEW (i.e.
Definition view.cpp:602
std::vector< VIEW_LAYER * > m_orderedLayers
Sorted list of pointers to members of m_layers.
Definition view.h:882
void clearGroupCache()
Clear cached GAL group numbers (ONLY numbers stored in VIEW_ITEMs, not group objects used by GAL).
Definition view.cpp:1244
VECTOR2D m_center
Center point of the VIEW (the point at which we are looking at).
Definition view.h:891
void SortOrderedLayers()
Sorts m_orderedLayers after layer rendering order has changed.
Definition view.cpp:1295
void MarkTargetDirty(int aTarget)
Set or clear target 'dirty' flag.
Definition view.h:648
void updateBbox(VIEW_ITEM *aItem)
Update bounding box of an item.
Definition view.cpp:1365
bool IsVisible(const VIEW_ITEM *aItem) const
Return information if the item is visible (or not).
Definition view.cpp:1697
void UpdateAllItemsConditionally(int aUpdateFlags, std::function< bool(VIEW_ITEM *)> aCondition)
Update items in the view according to the given flags and condition.
Definition view.cpp:1600
void SetVisible(VIEW_ITEM *aItem, bool aIsVisible=true)
Set the item visibility.
Definition view.cpp:1654
void ReorderLayerData(std::unordered_map< int, int > aReorderMap)
Remap the data between layer ids without invalidating that data.
Definition view.cpp:687
void redrawRect(const BOX2I &aRect)
Redraw contents within rectangle aRect.
Definition view.cpp:1018
VECTOR2< T > GetScale() const
Get the scale components of the matrix.
Definition matrix3x3.h:295
A small class to help profiling.
Definition profile.h:49
void Stop()
Save the time when this function was called, and set the counter stane to stop.
Definition profile.h:88
double msecs(bool aSinceLast=false)
Definition profile.h:149
Represent a set of closed polygons.
bool IsEmpty() const
Return true if the set is empty (no polygons at all)
void Deflate(int aAmount, CORNER_STRATEGY aCornerStrategy, int aMaxError)
void BooleanSubtract(const SHAPE_POLY_SET &b)
Perform boolean polyset difference.
const BOX2I BBox(int aClearance=0) const override
Compute a bounding box of the shape, with a margin of aClearance a collision.
@ ALLOW_ACUTE_CORNERS
just inflate the polygon. Acute angles create spikes
#define _(s)
const wxChar *const traceGalProfile
Flag to enable debug output of GAL performance profiling.
@ UNDEFINED_LAYER
Definition layer_ids.h:61
MATRIX3x3< double > MATRIX3x3D
Definition matrix3x3.h:473
The Cairo implementation of the graphics abstraction layer.
Definition eda_group.h:33
@ COLOR
Color has changed.
Definition view_item.h:54
@ INITIAL_ADD
Item is being added to the view.
Definition view_item.h:57
@ NONE
No updates are required.
Definition view_item.h:52
@ REPAINT
Item needs to be redrawn.
Definition view_item.h:58
@ APPEARANCE
Visibility flag has changed.
Definition view_item.h:53
@ GEOMETRY
Position or shape has changed.
Definition view_item.h:55
@ LAYERS
Layers have changed.
Definition view_item.h:56
@ ALL
All except INITIAL_ADD.
Definition view_item.h:59
@ TARGET_NONCACHED
Auxiliary rendering target (noncached)
Definition definitions.h:38
@ TARGET_CACHED
Main rendering target (cached)
Definition definitions.h:37
@ TARGET_OVERLAY
Items that may change while the view stays the same (noncached)
Definition definitions.h:39
@ HIDDEN
Item is temporarily hidden (usually in favor of a being drawn from an overlay, such as a SELECTION).
Definition view_item.h:70
@ OVERLAY_HIDDEN
Item is temporarily hidden from being drawn on an overlay.
Definition view_item.h:71
@ VISIBLE
Item is visible (in general)
Definition view_item.h:66
std::shared_ptr< PNS_LOG_VIEWER_OVERLAY > overlay
bool operator()(VIEW_ITEM *aItem)
Definition view.cpp:1233
bool operator()(VIEW_ITEM *aItem)
Definition view.cpp:958
DRAW_ITEM_VISITOR(VIEW *aView, int aLayer, bool aUseDrawPriority, bool aReverseDrawOrder)
Definition view.cpp:948
int layers[VIEW_MAX_LAYERS]
Definition view.cpp:1010
std::vector< VIEW_ITEM * > drawItems
Definition view.cpp:1012
bool operator()(VIEW_ITEM *aItem)
Definition view.cpp:1126
RECACHE_ITEM_VISITOR(VIEW *aView, GAL *aGal, int aLayer)
Definition view.cpp:1119
bool operator()(VIEW_ITEM *aItem)
Definition view.cpp:744
UPDATE_COLOR_VISITOR(int aLayer, PAINTER *aPainter, GAL *aGal)
Definition view.cpp:737
UPDATE_DEPTH_VISITOR(int aLayer, int aDepth, GAL *aGal)
Definition view.cpp:816
bool operator()(VIEW_ITEM *aItem)
Definition view.cpp:823
bool diffLayer
Layer should be drawn differentially over lower layers.
Definition view.h:774
int renderingOrder
Rendering order of this layer.
Definition view.h:779
bool hasNegatives
Layer should be drawn separately to not delete lower layers.
Definition view.h:777
bool visible
Is the layer to be rendered?
Definition view.h:770
bool displayOnly
Is the layer display only?
Definition view.h:771
std::shared_ptr< VIEW_RTREE > items
R-tree indexing all items on this layer.
Definition view.h:778
RENDER_TARGET target
Where the layer should be rendered.
Definition view.h:781
int id
Layer ID.
Definition view.h:780
int delta
wxLogTrace helper definitions.
#define KI_TRACE(aWhat,...)
VECTOR2< int32_t > VECTOR2I
Definition vector2d.h:695
VECTOR2< double > VECTOR2D
Definition vector2d.h:694