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