gwnavgeneration/boundary/connectedpattern.h Source File

connectedpattern.h
Go to the documentation of this file.
1 /*
2 * Copyright 2016 Autodesk, Inc. All rights reserved.
3 * Use of this software is subject to the terms of the Autodesk license agreement and any attachments or Appendices thereto provided at the time of installation or download,
4 * or which otherwise accompanies this software in either electronic or hard copy form, or which is signed by you and accepted by Autodesk.
5 */
6 
7 #pragma once
8 
13 
14 namespace Kaim
15 {
16 
17 static const KyUInt32 MaxVertexEdgeLinkCount = 8;
18 
19 
20 class VertexEdgeLink
21 {
22  KY_DEFINE_NEW_DELETE_OPERATORS(Stat_Default_Mem)
23 public:
24  enum EdgeInOrOut { EDGE_IN = 0, EDGE_OUT = 1 };
25 
26  void Init(EdgeInOrOut edgeInOrOut, BoundaryEdge* edge)
27  {
28  m_edge = edge;
29  m_edgeInOrOut = edgeInOrOut;
30  m_vertexIdxInEdge = (edgeInOrOut == EDGE_IN) ? 1 : 0;
31  }
32 
33  void Apply(BoundaryVertex* center)
34  {
35  m_edge->m_vertex[m_vertexIdxInEdge] = center; // edge.vertex = center
36  KY_ASSERT(m_edge->m_orientation < 4);
37  if (m_edgeInOrOut == EDGE_OUT)
38  center->m_outs[m_edge->m_orientation] = m_edge; // center.edges = edge
39  else
40  center->m_ins[m_edge->m_orientation] = m_edge; // center.edges = edge
41  }
42 
43  BoundaryEdge* m_edge;
44  EdgeInOrOut m_edgeInOrOut;
45  KyUInt32 m_vertexIdxInEdge;
46 };
47 
48 
49 class SquarePixel
50 {
51  KY_DEFINE_NEW_DELETE_OPERATORS(MemStat_NavDataGen)
52 public:
53  SquarePixel() { Setup(nullptr, 0, false); }
54 
55  void Setup(BoundaryPixel* boundaryPixel, KyUInt32 pixelIdxInSquare, bool isOutsideCellBox)
56  {
57  m_boundaryPixel = boundaryPixel;
58  m_connected[0] = nullptr;
59  m_connected[1] = nullptr;
60  m_pixelIdxInSquare = pixelIdxInSquare;
61  m_isInPattern = false;
62  m_isOutsideCellBox = isOutsideCellBox;
63  }
64 
65  // ORTHOGONAL EDGES
66  // +-----------+-----------+ pixel_0.edgeIn edgeLocationInLeftPixel=0 edgeDir = North = 1
67  // | 1 | 1 | pixel_1.edgeIn edgeLocationInLeftPixel=1 edgeDir = West = 2
68  // | p3 | p2 | pixel_2.edgeIn edgeLocationInLeftPixel=2 edgeDir = South = 3
69  // |2 out=0|2=in 0| pixel_3.edgeIn edgeLocationInLeftPixel=3 edgeDir = East = 0
70  // | | |
71  // | in=3 N 3=out | pixel_0.edgeOut edgeLocationInLeftPixel=1 edgeDir = West = 2
72  // +---------W-V-E---------+ pixel_1.edgeOut edgeLocationInLeftPixel=2 edgeDir = South = 3
73  // | out=1 S in=1 | pixel_2.edgeOut edgeLocationInLeftPixel=3 edgeDir = East = 0
74  // | | | pixel_3.edgeOut edgeLocationInLeftPixel=0 edgeDir = North = 1
75  // |2 in=0|2=out 0|
76  // | p0 | p1 | edgeDirFromCenter:
77  // | 3 | 3 | E=East=0 N=North=1 W=West=2 S=South=3
78  // +-----------+-----------+
79 
80  void PushVertexEdgeLinks(VertexEdgeLink* vertexEdgeLinks, KyUInt32& vertexEdgeLinksCount) const
81  {
82  CardinalDir edgeIn_IdxInPixel = m_pixelIdxInSquare;
83  CardinalDir edgeOut_IdxInPixel = GetNextCardinalDir_CCW(edgeIn_IdxInPixel);
84 
85  BoundaryEdge* edgeIn = m_boundaryPixel->m_edges[edgeIn_IdxInPixel];
86  if (edgeIn != nullptr)
87  {
88  KY_ASSERT(vertexEdgeLinksCount < MaxVertexEdgeLinkCount);
89  VertexEdgeLink& link = vertexEdgeLinks[vertexEdgeLinksCount++];
90  link.Init(VertexEdgeLink::EDGE_IN, edgeIn);
91  }
92 
93  BoundaryEdge* edgeOut = m_boundaryPixel->m_edges[edgeOut_IdxInPixel];
94  if (edgeOut != nullptr)
95  {
96  KY_ASSERT(vertexEdgeLinksCount < MaxVertexEdgeLinkCount);
97  VertexEdgeLink& link = vertexEdgeLinks[vertexEdgeLinksCount++];
98  link.Init(VertexEdgeLink::EDGE_OUT, edgeOut);
99  }
100  }
101 
102  BoundaryPixel* m_boundaryPixel;
103  SquarePixel* m_connected[2];
104  KyUInt32 m_pixelIdxInSquare;
105  bool m_isInPattern;
106  bool m_isOutsideCellBox;
107 };
108 
109 
110 class SquarePixelColumn
111 {
112  KY_DEFINE_NEW_DELETE_OPERATORS(Stat_Default_Mem)
113 public:
114  SquarePixelColumn(KyUInt32 squarePixelsCapacityAtInit = 50)
115  {
116  if (squarePixelsCapacityAtInit == 0)
117  squarePixelsCapacityAtInit = 50;
118  m_squarePixels.Resize(squarePixelsCapacityAtInit);
119  }
120 
121  ~SquarePixelColumn() {}
122 
123  void Setup(KyUInt32 idxInSquare, const NavBoundaryPos& pos, const BoxOfArrays<BoundaryPixel>::Column& boundaryPixelColumn, bool isOutsideNavBox)
124  {
125  m_pos = pos;
126  m_squarePixels.Clear();
127  m_squarePixels.Resize(boundaryPixelColumn.m_count);
128  for (NavRasterFloorIdx floorIdx = 0; floorIdx < boundaryPixelColumn.m_count; ++floorIdx)
129  m_squarePixels[floorIdx].Setup(&boundaryPixelColumn.m_values[floorIdx], idxInSquare, isOutsideNavBox);
130  }
131 
132  PixelPos m_pos;
133  KyArrayTLS_POD<SquarePixel> m_squarePixels;
134 };
135 
136 
137 class ConnectionSquare
138 {
139  KY_DEFINE_NEW_DELETE_OPERATORS(Stat_Default_Mem)
140 public:
141  KY_INLINE void SetupSquarePixelColumn(KyUInt32 idxInSquare, const NavBoundaryPos& pos, const BoxOfArrays<BoundaryPixel>::Column& boundaryPixelColumn, bool isOutsideNavBox)
142  {
143  m_columns[idxInSquare].Setup(idxInSquare, pos, boundaryPixelColumn, isOutsideNavBox);
144  }
145 public:
146  SquarePixelColumn m_columns[4];
147 };
148 
149 
150 class ConnectedPattern
151 {
152  KY_DEFINE_NEW_DELETE_OPERATORS(Stat_Default_Mem)
153 public:
154  enum { CCW = 0, CW = 1 };
155 
156  ConnectedPattern() : m_count(0)
157  {
158  for(KyUInt32 i = 0; i < 4; ++i)
159  m_pixels[i] = nullptr;
160  }
161 
162  void Init(SquarePixel* firstSquarePixel)
163  {
164  // push first
165  firstSquarePixel->m_isInPattern = true;
166  m_pixels[0] = firstSquarePixel;
167  m_count = 1;
168 
169  // propagate CCW and CW
170  for(KyUInt32 i = 0; i < 2; ++i)
171  {
172  SquarePixel* squarePixel = firstSquarePixel;
173  for (;;)
174  {
175  squarePixel = squarePixel->m_connected[i];
176  if (squarePixel == nullptr || squarePixel->m_isInPattern == true)
177  break;
178  squarePixel->m_isInPattern = true;
179  if (m_count < 4)
180  m_pixels[m_count] = squarePixel;
181  m_count++;
182  }
183  }
184  }
185 
186  KyFloat32 GetCenterAltitude()
187  {
188  KY_ASSERT(m_count != 0);
189  static const KyFloat32 florCountInv[4] = { 1.f, 0.5f, 0.333333333333f, 0.25f };
190 
191  KyFloat32 altitude = 0.0f;
192  for (KyUInt32 i = 0; i < m_count; ++i)
193  {
194  KY_ASSERT(m_pixels[i] != nullptr);
195  altitude += m_pixels[i]->m_boundaryPixel->m_navRasterPixel->m_altitude;
196  }
197  altitude *= florCountInv[m_count-1];
198  return altitude;
199  }
200 
201  bool IsFullyOutsideCellBox()
202  {
203  KY_ASSERT(m_count != 0);
204  for (KyUInt32 i = 0; i < m_count; ++i)
205  {
206  if (m_pixels[i]->m_isOutsideCellBox == false)
207  return false;
208  }
209  return true;
210  }
211 
212  bool IsNarrow()
213  {
214  bool isBlocked[4] = { false, false, false, false };
215  bool isDeadEnd[4] = { false, false, false, false };
216  for (KyUInt32 pixelIdx = 0; pixelIdx < m_count; ++pixelIdx)
217  {
218  SquarePixel* squarePixel = m_pixels[pixelIdx];
219  KY_ASSERT(squarePixel != nullptr);
220 
221  BoundaryPixel* boundaryPixel = squarePixel->m_boundaryPixel;
222  KY_ASSERT(boundaryPixel != nullptr);
223  // Dead end chedc
224  // Dead end == 3 consecutive orthogonal edges
225  for (CardinalDir dir = 0; dir < 4; ++dir)
226  {
227  // 3 consecutive orthogonal edges == dead end -> NOT necessarily narrow
228  const BoundaryEdge* edges[4] =
229  {
230  boundaryPixel->m_edges[ dir ], // current dir
231  boundaryPixel->m_edges[(dir+1)%4],
232  boundaryPixel->m_edges[(dir+2)%4],
233  boundaryPixel->m_edges[(dir+3)%4]
234  };
235 
236  if (edges[0] != nullptr && edges[1] != nullptr && edges[2] != nullptr)
237  {
238  isDeadEnd[pixelIdx] = true;
239  if (edges[3] != nullptr)
240  return true; // 4 consecutive edges: isolated pixel <=> narrow otherwise simplified polyline will fail
241 
242  break;
243  }
244  }
245 
246  if (isDeadEnd[pixelIdx] == false)
247  {
248  for (CardinalDir dir = 0; dir < 4; ++dir)
249  {
250  // 2 opposite orthogonal edges and not deadEnd == 1 pixel corridor -> narrow
251  // =====
252  // | p |
253  // =====
254  if (squarePixel->m_boundaryPixel->m_edges[ dir ] != nullptr &&
255  squarePixel->m_boundaryPixel->m_edges[GetOppositeCardinalDir(dir)]!= nullptr )
256  return true;
257  }
258  }
259 
260  // 2
261  // +--e2--+---e2-+ pixel 0: (right) e4 -> vertex 3 is blocked
262  // | | | (up) e6 -> vertex 0 is blocked
263  // e4 p3 | p2 e0 pixel 1: (right) e6 -> vertex 0 is blocked
264  // 3 +------+----- + 1 (up) e0 -> vertex 1 is blocked
265  // | p0 | p1 | pixel 2: (right) e0 -> vertex 1 is blocked
266  // e4 | e0 (up) e2 -> vertex 2 is blocked
267  // +---e6-+--e6--+ pixel 3: (right) e2 -> vertex 2 is blocked
268  // 0 (up) e4 -> vertex 3 is blocked
269 
270  KyUInt32 rightEdgeIdx = (squarePixel->m_pixelIdxInSquare + 2) % 4; // ~= opposite
271  KyUInt32 upEdgeIdx = (squarePixel->m_pixelIdxInSquare + 3) % 4;
272  KyUInt32 rightVtxIdx = (squarePixel->m_pixelIdxInSquare + 3) % 4;
273  KyUInt32 upVtxIdx = (squarePixel->m_pixelIdxInSquare);
274 
275  if (isBlocked[rightVtxIdx] == false && squarePixel->m_boundaryPixel->m_edges[rightEdgeIdx])
276  isBlocked[rightVtxIdx] = true;
277 
278  if (isBlocked[upVtxIdx] == false && squarePixel->m_boundaryPixel->m_edges[upEdgeIdx])
279  isBlocked[upVtxIdx] = true;
280  }
281 
282  // 2 U shaped pixels attached = narrow corridor !
283  // ==========
284  // | p0 - p1 |
285  // ==========
286  //
287  for (KyUInt32 j = 0; j < 4; ++j)
288  {
289  if (isDeadEnd[j] && isDeadEnd[(j+1)%4])
290  return true;
291  }
292 
293  //if a vertex is blocked but no edge links pattern center to it, we have a narrow pattern
294  for (KyUInt32 pixelIdx = 0; pixelIdx < m_count; ++pixelIdx)
295  {
296  if (isDeadEnd[pixelIdx])
297  continue;
298 
299  SquarePixel* squarePixel = m_pixels[pixelIdx];
300  KY_ASSERT(squarePixel != nullptr);
301 
302  SquarePixel* neighborCCW = squarePixel->m_connected[CCW];
303  if (neighborCCW != nullptr)
304  {
305  KyUInt32 ccwVtxIdx = (squarePixel->m_pixelIdxInSquare);
306  if (isBlocked[ccwVtxIdx] &&
307  neighborCCW->m_boundaryPixel->m_floorColor == squarePixel->m_boundaryPixel->m_floorColor &&
308  neighborCCW->m_boundaryPixel->m_connexIdx == squarePixel->m_boundaryPixel->m_connexIdx )
309  return true;
310  }
311 
312  SquarePixel* neighborCW = squarePixel->m_connected[CW];
313  if (neighborCW != nullptr)
314  {
315  KyUInt32 cwVtxIdx = (squarePixel->m_pixelIdxInSquare + 3) % 4;
316  if (isBlocked[cwVtxIdx] &&
317  neighborCW->m_boundaryPixel->m_floorColor == squarePixel->m_boundaryPixel->m_floorColor &&
318  neighborCW->m_boundaryPixel->m_connexIdx == squarePixel->m_boundaryPixel->m_connexIdx )
319  return true;
320  }
321  }
322  return false;
323  }
324 
325  KyUInt32 m_count; // in [0; 4]
326  SquarePixel* m_pixels[4];
327 };
328 }
329 
330 
std::uint32_t KyUInt32
uint32_t
Definition: types.h:29
KyUInt32 CardinalDir
Defines a type that refers to one of the cardinal points on the compass:
Definition: cardinaldir.h:15
#define KY_DEFINE_NEW_DELETE_OPERATORS(MemStat)
This macro defines new and delete operators.
Definition: memory.h:132
The Autodesk Navigation namespace.
Definition: gamekitcrowddispersion.cpp:17
float KyFloat32
float
Definition: types.h:32