KiCad PCB EDA Suite
Loading...
Searching...
No Matches
drc_zone_index.h
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 The KiCad Developers, see AUTHORS.txt for contributors.
5 *
6 * This program is free software; you can redistribute it and/or
7 * modify it under the terms of the GNU General Public License
8 * as published by the Free Software Foundation; either version 3
9 * of the License, or (at your option) any later version.
10 */
11
12#ifndef DRC_ZONE_INDEX_H
13#define DRC_ZONE_INDEX_H
14
15#include <algorithm>
16#include <map>
17#include <optional>
18#include <utility>
19#include <vector>
20
22#include <math/box2.h>
23#include <zone.h>
24
34template <typename BOX_FN>
35std::vector<std::pair<size_t, size_t>> CollectOverlappingPairs( const std::vector<size_t>& aOrderedIndices,
36 BOX_FN aBox )
37{
39
40 std::vector<std::pair<size_t, size_t>> pairs;
41 std::vector<BOX2I> boxes( aOrderedIndices.size() );
42 std::vector<char> present( aOrderedIndices.size(), 0 );
43 PAIR_TREE::Builder builder;
44
45 builder.Reserve( aOrderedIndices.size() );
46
47 for( size_t pos = 0; pos < aOrderedIndices.size(); ++pos )
48 {
49 std::optional<BOX2I> box = aBox( aOrderedIndices[pos] );
50
51 if( !box )
52 continue;
53
54 box->Normalize();
55 boxes[pos] = *box;
56 present[pos] = 1;
57
58 const int min[2] = { box->GetX(), box->GetY() };
59 const int max[2] = { box->GetRight(), box->GetBottom() };
60 builder.Add( min, max, pos );
61 }
62
63 PAIR_TREE tree = builder.Build();
64 std::vector<size_t> overlaps;
65 size_t pos = 0;
66
67 // Positions, not caller indices, so the emission order matches the vector
68 auto visitor =
69 [&]( size_t aOther )
70 {
71 if( aOther > pos )
72 overlaps.push_back( aOther );
73
74 return true;
75 };
76
77 for( pos = 0; pos < aOrderedIndices.size(); ++pos )
78 {
79 if( !present[pos] )
80 continue;
81
82 overlaps.clear();
83
84 const int min[2] = { boxes[pos].GetX(), boxes[pos].GetY() };
85 const int max[2] = { boxes[pos].GetRight(), boxes[pos].GetBottom() };
86
87 tree.Search( min, max, visitor );
88
89 std::sort( overlaps.begin(), overlaps.end() );
90
91 for( size_t other : overlaps )
92 pairs.emplace_back( aOrderedIndices[pos], aOrderedIndices[other] );
93 }
94
95 return pairs;
96}
97
98
100{
101public:
102 void Build( const std::map<PCB_LAYER_ID, std::vector<ZONE*>>& aLayers )
103 {
104 Clear();
105
106 for( const auto& [layer, zones] : aLayers )
107 {
108 TREE::Builder builder;
109 builder.Reserve( zones.size() );
110 m_zones[layer] = zones;
111
112 for( size_t ordinal = 0; ordinal < zones.size(); ++ordinal )
113 {
114 BOX2I bbox = zones[ordinal]->GetBoundingBox();
115 bbox.Normalize();
116 int min[2] = { bbox.GetX(), bbox.GetY() };
117 int max[2] = { bbox.GetRight(), bbox.GetBottom() };
118 builder.Add( min, max, ordinal );
119 }
120
121 m_trees.emplace( layer, builder.Build() );
122 }
123 }
124
126 bool HasLayer( PCB_LAYER_ID aLayer ) const { return m_trees.find( aLayer ) != m_trees.end(); }
127
128 void Query( PCB_LAYER_ID aLayer, const BOX2I& aBox, std::vector<ZONE*>& aOut ) const
129 {
130 aOut.clear();
131 auto treeIt = m_trees.find( aLayer );
132 auto zonesIt = m_zones.find( aLayer );
133
134 if( treeIt == m_trees.end() || zonesIt == m_zones.end() )
135 return;
136
137 BOX2I bbox = aBox;
138 bbox.Normalize();
139 int min[2] = { bbox.GetX(), bbox.GetY() };
140 int max[2] = { bbox.GetRight(), bbox.GetBottom() };
141 std::vector<size_t> ordinals;
142
143 auto visitor =
144 [&]( size_t aOrdinal )
145 {
146 ordinals.push_back( aOrdinal );
147 return true;
148 };
149
150 treeIt->second.Search( min, max, visitor );
151
152 std::sort( ordinals.begin(), ordinals.end() );
153 aOut.reserve( ordinals.size() );
154
155 for( size_t ordinal : ordinals )
156 aOut.push_back( zonesIt->second[ordinal] );
157 }
158
159 void Clear()
160 {
161 m_trees.clear();
162 m_zones.clear();
163 }
164
165private:
167
168 std::map<PCB_LAYER_ID, TREE> m_trees;
169 std::map<PCB_LAYER_ID, std::vector<ZONE*>> m_zones;
170};
171
172#endif // DRC_ZONE_INDEX_H
BOX2< VECTOR2I > BOX2I
Definition box2.h:914
constexpr BOX2< Vec > & Normalize()
Ensure that the height and width are positive.
Definition box2.h:143
constexpr coord_type GetY() const
Definition box2.h:205
constexpr coord_type GetX() const
Definition box2.h:204
constexpr coord_type GetRight() const
Definition box2.h:214
constexpr coord_type GetBottom() const
Definition box2.h:219
std::map< PCB_LAYER_ID, std::vector< ZONE * > > m_zones
bool HasLayer(PCB_LAYER_ID aLayer) const
True when the layer holds at least one zone, so a caller can skip building a query box.
void Build(const std::map< PCB_LAYER_ID, std::vector< ZONE * > > &aLayers)
std::map< PCB_LAYER_ID, TREE > m_trees
KIRTREE::PACKED_RTREE< size_t, int, 2 > TREE
void Query(PCB_LAYER_ID aLayer, const BOX2I &aBox, std::vector< ZONE * > &aOut) const
Static (immutable) packed R-tree built via Hilbert-curve bulk loading.
std::vector< std::pair< size_t, size_t > > CollectOverlappingPairs(const std::vector< size_t > &aOrderedIndices, BOX_FN aBox)
Enumerate the pairs of aOrderedIndices whose boxes overlap, in the order a nested loop over the vecto...
PCB_LAYER_ID
A quick note on layer IDs:
Definition layer_ids.h:56