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