Arma Reforger Explorer 1.7.0.54
Arma Reforger Code Explorer by Zeroy - Thanks to MisterOutofTime
Loading...
Searching...
No Matches
SCR_ShapeNextPointHelper.c
Go to the documentation of this file.
1
7
8// TODO:
9// - in shape's length (straightLine parameter)
10
12{
13 protected ref array<vector> m_aAnchorPoints;
14 protected ref array<vector> m_aTesselatedPoints;
15 protected ref array<int> m_aAnchorPointIndices;
16 protected ref array<ref array<vector>> m_aSegments;
17 protected ref array<ref array<vector>> m_aSections;
18// protected ref array<ref array<float>> m_aSectionLengths; //!< format [anchor0to1shapeLength, anchor1to2shapeLength] - shape length = length following the spline
19 protected int m_iSegmentsCount;
20 protected int m_iAnchorPointsCount;
21// protected int m_iTesselatedPointsCount; //!< count of m_aTesselatedPoints
22
28
29 protected float m_fDoneLength;
30 protected float m_fTotalLength;
31
32 //------------------------------------------------------------------------------------------------
34 array<vector> GetAnchorPoints()
35 {
36 return SCR_ArrayHelperT<vector>.GetCopy(m_aAnchorPoints);
37 }
38
39 //------------------------------------------------------------------------------------------------
42 {
43 return SCR_ArrayHelperT<int>.GetCopy(m_aAnchorPointIndices);
44 }
45
46 //------------------------------------------------------------------------------------------------
48 array<vector> GetTesselatedPoints()
49 {
50 return SCR_ArrayHelperT<vector>.GetCopy(m_aTesselatedPoints);
51 }
52
53 //------------------------------------------------------------------------------------------------
59
60 //------------------------------------------------------------------------------------------------
66
67 //------------------------------------------------------------------------------------------------
70 {
71 return m_fTotalLength;
72 }
73
74 //------------------------------------------------------------------------------------------------
77 {
78 return m_fDoneLength;
79 }
80
81 //------------------------------------------------------------------------------------------------
87
88 //------------------------------------------------------------------------------------------------
89 // bruteforce for now, optimisation later
91 {
92 float currentSegmentIndex;
93 for (int i; i < m_iCurrentSectionIndex; ++i)
94 {
95 currentSegmentIndex += m_aSections[i].Count() - 1;
96 }
97
98 return currentSegmentIndex + m_iCurrentSectionPointIndex;
99 }
100
101 //------------------------------------------------------------------------------------------------
102 // bruteforce for now, optimisation later
103 protected float CalculateDoneLength()
104 {
105 float doneLength;
106 foreach (int i, array<vector> segment : m_aSegments)
107 {
108 if (i >= m_iCurrentSegmentIndex)
109 {
110 doneLength += vector.Distance(segment[0], m_vCurrentPosition);
111 return doneLength;
112 }
113
114 doneLength += vector.Distance(segment[0], segment[1]);
115 }
116
117 return -1;
118 }
119
120 //------------------------------------------------------------------------------------------------
129 bool GetNextPoint(float distance, out vector result, int anchorLimit = -1, bool straightLine = true, bool doNotMove = false, bool xzMode = false)
130 {
131 if (distance <= 0)
132 {
133 Print("SCR_ShapeNextPointHelper.GetNextPoint's distance parameter cannot be zero or negative!", LogLevel.ERROR);
134 return false; // wrong distance
135 }
136
137 if (anchorLimit == -1)
138 anchorLimit = m_iAnchorPointsCount - 1;
139
140 if (anchorLimit < 1 || anchorLimit >= m_iAnchorPointsCount)
141 {
142 Print("SCR_ShapeNextPointHelper.GetNextPoint's anchorLimit parameter is invalid (must be in range 1.." + m_iAnchorPointsCount + ", was " + anchorLimit + ")", LogLevel.ERROR);
143 return false;
144 }
145
146 if (anchorLimit <= m_iCurrentSectionIndex)
147 {
148 Print("SCR_ShapeNextPointHelper.GetNextPoint's anchorLimit parameter is already passed (" + anchorLimit + " requested, " + m_iCurrentSectionIndex + " current)", LogLevel.WARNING);
149 return false;
150 }
151
152 float distanceSq = distance * distance;
153
154 int currentSectionIndex = m_iCurrentSectionIndex;
155 int currentSectionPoint = m_iCurrentSectionPointIndex + 1;
156// float addedLength;
157
158 if (!m_aSections[currentSectionIndex].IsIndexValid(currentSectionPoint))
159 {
160 currentSectionIndex++;
161 currentSectionPoint = 1; // because end point of previous section = first point of next section
162 }
163
165
166 array<vector> sectionPoints;
167// array<float> sectionSegmentsLength;
168 for (; currentSectionIndex < anchorLimit; currentSectionIndex++)
169 {
170 sectionPoints = m_aSections[currentSectionIndex];
171// sectionSegmentsLength = m_aSectionLengths[currentSectionIndex];
172
173 for (int pointIndex = currentSectionPoint, sectionPointsCount = sectionPoints.Count(); pointIndex < sectionPointsCount; pointIndex++)
174 {
175 vector nextPoint = sectionPoints[pointIndex];
176// if (straightLine)
177// {
178 if (
179 (xzMode && vector.DistanceSqXZ(m_vCurrentPosition, nextPoint) > distanceSq) || // 2D mode
180 (!xzMode && vector.DistanceSq(m_vCurrentPosition, nextPoint) > distanceSq)) // 3D mode
181 {
182 vector endToStartDir = vector.Direction(nextPoint, prevPoint);
183 if (xzMode) // 2D mode - there must exist a better formula, todo later
184 {
185 vector endToStartDirXZ = endToStartDir;
186 endToStartDirXZ[1] = 0;
187 vector sameLevelCentre = m_vCurrentPosition;
188 sameLevelCentre[1] = nextPoint[1];
189 float removedRatio;
190 if (vector.DistanceXZ(nextPoint, prevPoint) != 0)
191 removedRatio =
192 Math3D.IntersectionRaySphere(nextPoint, endToStartDirXZ.Normalized(), sameLevelCentre, distance)
193 / vector.DistanceXZ(nextPoint, prevPoint);
194
195 result = nextPoint + removedRatio * endToStartDirXZ;
196 result[1] = prevPoint[1] + (1 - removedRatio) * (nextPoint[1] - prevPoint[1]);
197 }
198 else // 3D mode
199 {
200 endToStartDir.Normalize(); // "variable reuse"
201 result = nextPoint + endToStartDir * Math3D.IntersectionRaySphere(nextPoint, endToStartDir, m_vCurrentPosition, distance);
202 }
203
204 if (!doNotMove)
205 {
206 m_vCurrentPosition = result;
207 m_vCurrentDirection = vector.Direction(prevPoint, nextPoint).Normalized(); // TODO: on vertices
208 m_iCurrentSectionIndex = currentSectionIndex;
209 m_iCurrentSectionPointIndex = pointIndex - 1;
210// m_fDoneLength += addedLength + vector.Distance(prevPoint, result);
211
214 }
215
216 return true;
217 }
218// }
219// else // in shape's length
220// {
221// if (addedLength + sectionSegmentsLength[pointIndex] > distance)
222// {
223// float remainder = distance - addedLength;
224// vector prevToNextDirNormalised = vector.Direction(prevPoint, nextPoint).Normalized();
225// result = prevPoint + prevToNextDirNormalised * remainder;
226//
227// if (!doNotMove)
228// {
229// m_vCurrentPosition = result;
230// m_iCurrentSectionIndex = currentSectionIndex;
231// m_iCurrentSectionPointIndex = pointIndex - 1;
232// m_fDoneLength += distance;
233// }
234//
235// return true;
236// }
237// }
238
239// addedLength += sectionSegmentsLength[pointIndex];
240 prevPoint = nextPoint;
241 }
242
243 currentSectionPoint = 1; // because end point of previous section = first point of next section
244 }
245
246 return false; // shape end
247 }
248
249 //------------------------------------------------------------------------------------------------
252 {
253 float result = vector.Distance(m_vCurrentPosition, m_aSegments[m_iCurrentSegmentIndex][1]);
254 if (result == 0)
255 return 0;
256
257 array<vector> segment;
258 for (int i = m_iCurrentSegmentIndex + 1; i < m_iSegmentsCount; i++)
259 {
260 segment = m_aSegments[i];
261 result += vector.Distance(segment[0], segment[1]);
262 if (m_aAnchorPoints.Contains(segment[1]))
263 return result;
264 }
265//TODO
266 return result;
267 }
268
269 //------------------------------------------------------------------------------------------------
278
279 //------------------------------------------------------------------------------------------------
283 bool SetOnAnchor(int anchorIndex)
284 {
285 if (anchorIndex < 0 || anchorIndex >= m_iAnchorPointsCount)
286 return false;
287
288 m_vCurrentPosition = m_aAnchorPoints[anchorIndex];
289
290 vector prevPoint;
291 vector nextPoint;
292 if (anchorIndex == 0) // start
293 {
294 m_vCurrentDirection = vector.Direction(m_aSegments[0][0], m_aSegments[0][1]).Normalized();
295 }
296 else if (anchorIndex == m_iAnchorPointsCount - 1) // end
297 {
298 m_vCurrentDirection = vector.Direction(m_aSegments[m_iSegmentsCount - 1][0], m_aSegments[m_iSegmentsCount - 1][1]).Normalized();
299 }
300 else // middle
301 {
302 // just a direction of prevNorm to nextNorm, not accurate - TODO: fix
303 m_vCurrentDirection = vector.Direction(
304 vector.Direction(m_vCurrentPosition, m_aAnchorPoints[anchorIndex - 1]).Normalized(),
305 vector.Direction(m_vCurrentPosition, m_aAnchorPoints[anchorIndex + 1]).Normalized()
306 ).Normalized();
307 }
308
309 m_iCurrentSectionIndex = anchorIndex;
311
314
315 return true;
316 }
317
318// //------------------------------------------------------------------------------------------------
319// //! Sets to the provided position IF on the shape
320// //! \param[in] position the wanted (relative) position
321// //! \return true on success, false on failure
322// bool SetPos(vector position)
323// {
324// foreach (int segmentIndex, array<vector> segment : m_aSegments)
325// {
326// if (
327// (segmentIndex == m_iSegmentsCount - 1 || position != segment[1]) && // on start point, not on end
328// Math3D.PointLineSegmentDistanceSqr(position, segment[0], segment[1]) < 0.001) // on segment
329// {
330// m_vCurrentPosition = position;
331// m_iCurrentSegmentIndex = segmentIndex;
332// return true;
333// }
334// }
335//
336// return false;
337// }
338
339 //------------------------------------------------------------------------------------------------
341 bool IsValid()
342 {
343 return m_iAnchorPointsCount > 1 && m_fTotalLength > 0;
344 }
345
346 //------------------------------------------------------------------------------------------------
348 void Reset()
349 {
350 if (m_iAnchorPointsCount > 0)
351 SetOnAnchor(0);
352 }
353
354 //--- constructors
355
356 //------------------------------------------------------------------------------------------------
361 static SCR_ShapeNextPointHelper CreateFromPoints(notnull array<vector> anchorPoints, notnull array<vector> tesselatedPoints)
362 {
363 int anchorPointsCount = anchorPoints.Count();
364 if (anchorPointsCount < 2)
365 return null;
366
367 int tesselatedPointsCount = tesselatedPoints.Count();
368 if (tesselatedPointsCount < anchorPointsCount)
369 return null;
370
371 // must have same first and last points
372 if (anchorPoints[0] != tesselatedPoints[0])
373 return null;
374
375// if (anchorPoints[anchorPointsCount - 1] != tesselatedPoints[tesselatedPointsCount - 1])
376// return null;
377
378 int anchorIndex;
379 vector anchorPos = anchorPoints[anchorIndex];
380 foreach (vector tesselatedPoint : tesselatedPoints)
381 {
382 if (anchorIndex >= anchorPointsCount) // found too many matches
383 break; // wrong detection
384
385 if (tesselatedPoint == anchorPoints[anchorIndex])
386 {
387 ++anchorIndex; // must break after the first point
388 if (anchorIndex < anchorPointsCount)
389 anchorPos = anchorPoints[anchorIndex];
390 }
391 }
392
393 if (anchorIndex != anchorPointsCount) // did not find all points
394 return null;
395
396 // everything OK? let's go
397
399
400 result.m_aAnchorPoints = SCR_ArrayHelperT<vector>.GetCopy(anchorPoints);
401 result.m_aAnchorPointIndices = {};
402 result.m_aTesselatedPoints = SCR_ArrayHelperT<vector>.GetCopy(tesselatedPoints);
403 result.m_aSections = {};
404// m_aSectionLengths = {};
405 array<vector> anchorSection;
406 array<float> sectionSegmentLengths;
407 result.m_aSegments = {};
408 anchorIndex = 0;
409 vector nextAnchor = result.m_aAnchorPoints[anchorIndex];
410
411 vector prevPoint;
412 foreach (int i, vector currPoint : result.m_aTesselatedPoints)
413 {
414 float segmentLength = vector.Distance(currPoint, prevPoint);
415
416 if (i > 0) // normal point or anchor point
417 {
418 anchorSection.Insert(currPoint);
419 sectionSegmentLengths.Insert(segmentLength);
420 result.m_aSegments.Insert({ prevPoint, currPoint });
421 }
422
423 if (currPoint == nextAnchor) // anchor point (including first and last ones)
424 {
425 result.m_aAnchorPointIndices.Insert(i);
426 if (i > 0) // everything but the first point
427 {
428 result.m_aSections.Insert(anchorSection);
429 sectionSegmentLengths.Insert(segmentLength);
430// m_aSectionLengths.Insert(sectionSegmentLengths);
431 }
432
433 anchorSection = { currPoint };
434 sectionSegmentLengths = {};
435
436 ++anchorIndex; // if last point, foreach ends and m_aAnchorPoints[maxIndex + 1] never occurs
437 if (anchorIndex >= anchorPointsCount)
438 anchorIndex = 0;
439
440 nextAnchor = result.m_aAnchorPoints[anchorIndex];
441 }
442
443 result.m_fTotalLength += segmentLength;
444
445 prevPoint = currPoint;
446 }
447
448 result.m_iAnchorPointsCount = anchorPointsCount;
449// result.m_iTesselatedPointsCount = tesselatedPointsCount;
450 result.m_iSegmentsCount = tesselatedPointsCount - 1;
451
452 result.SetOnAnchor(0); // sets m_vCurrentPosition & m_vCurrentDirection
453
454 return result;
455 }
456
457 //------------------------------------------------------------------------------------------------
462 static SCR_ShapeNextPointHelper CreateFromShape(notnull ShapeEntity shapeEntity, bool reverse = false)
463 {
464 array<vector> anchorPoints = {};
465 array<vector> tesselatedPoints = {};
466
467 shapeEntity.GetPointsPositions(anchorPoints);
468 shapeEntity.GenerateTesselatedShape(tesselatedPoints);
469
470 bool isShapeClosed = shapeEntity.IsClosed();
471
472#ifdef WORKBENCH
473 WorldEditorAPI worldEditorAPI = ((WorldEditor)Workbench.GetModule(WorldEditor)).GetApi();
474 if (worldEditorAPI)
475 {
476 IEntitySource shapeEntitySource = worldEditorAPI.EntityToSource(shapeEntity);
477 if (shapeEntitySource)
478 shapeEntitySource.Get("IsClosed", isShapeClosed);
479 }
480#endif // WORKBENCH
481
482 if (isShapeClosed)
483 {
484 anchorPoints.Insert(anchorPoints[0]);
485 if (!SplineShapeEntity.Cast(shapeEntity)) // spline already has the first tesselated point as last point
486 tesselatedPoints.Insert(tesselatedPoints[0]);
487 }
488
489 if (reverse)
490 {
491 SCR_ArrayHelperT<vector>.Reverse(anchorPoints);
492 SCR_ArrayHelperT<vector>.Reverse(tesselatedPoints);
493 }
494
495 return CreateFromPoints(anchorPoints, tesselatedPoints);
496 }
497
498 //------------------------------------------------------------------------------------------------
500 protected void SCR_ShapeNextPointHelper();
501}
float distance
static SCR_ShapeNextPointHelper CreateFromShape(notnull ShapeEntity shapeEntity, bool reverse=false)
static SCR_ShapeNextPointHelper CreateFromPoints(notnull array< vector > anchorPoints, notnull array< vector > tesselatedPoints)
void Reset()
Reset to the beginning.
ref array< vector > m_aAnchorPoints
format [anchor0, anchor1, anchor2]
int m_iSegmentsCount
count of m_aSegments
ref array< vector > m_aTesselatedPoints
format [anchor0, pointA0, pointB0, anchor1, pointA1, pointB1, anchor2]
int m_iAnchorPointsCount
count of m_aAnchorPoints
ref array< ref array< vector > > m_aSegments
format [[segment0startPos, segment0endPos], [segment1startPos, segment1endPos]]
void SCR_ShapeNextPointHelper()
protected constructor - use CreateFrom* methods
ref array< int > m_aAnchorPointIndices
anchor indices in tesselated points
bool GetNextPoint(float distance, out vector result, int anchorLimit=-1, bool straightLine=true, bool doNotMove=false, bool xzMode=false)
ref array< ref array< vector > > m_aSections
format [[anchor0, tessPoint, tessPoint, anchor1], [anchor1, tessPoint, tessPoint, anchor2]]
proto void Print(void var, LogLevel level=LogLevel.NORMAL)
Prints content of variable to console/log.
LogLevel
Enum with severity of the logging message.
Definition LogLevel.c:14
proto native bool IsIndexValid(int index)
Returns whether provided element index of array is valid.