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