Arma Reforger Explorer 1.7.0.54
Arma Reforger Code Explorer by Zeroy - Thanks to MisterOutofTime
Loading...
Searching...
No Matches
SCR_ParallelShapeHelper.c
Go to the documentation of this file.
1class SCR_ParallelShapeHelper // should be named SCR_OffsetShapeHelper
2{
3 //------------------------------------------------------------------------------------------------
11 static bool GetAnchorsAndTesselatedPointsFromShape(notnull ShapeEntity shapeEntity, vector offset, bool yOffsetInShapeSpace, out notnull array<vector> offsetAnchorPoints, out notnull array<vector> offsetTesselatedPoints, out array<int> offsetAnchorIndices = null)
12 {
13 if (!offsetAnchorPoints && !offsetTesselatedPoints && !offsetAnchorIndices)
14 return false;
15
16 array<vector> anchorPoints = {};
17 shapeEntity.GetPointsPositions(anchorPoints);
18 int anchorPointsCount = anchorPoints.Count();
19 if (anchorPointsCount < 2)
20 return false;
21
22 // spline
23 array<vector> tesselatedPoints = {};
24 shapeEntity.GenerateTesselatedShape(tesselatedPoints);
25 int tesselatedPointsCount = tesselatedPoints.Count();
26 if (tesselatedPointsCount < anchorPointsCount)
27 return false;
28
29 if (anchorPoints[0] != tesselatedPoints[0])
30 return false;
31
32 bool isShapeClosed = shapeEntity.IsClosed();
33
34#ifdef WORKBENCH
35 WorldEditorAPI worldEditorAPI = ((WorldEditor)Workbench.GetModule(WorldEditor)).GetApi();
36 if (worldEditorAPI)
37 {
38 IEntitySource shapeEntitySource = worldEditorAPI.EntityToSource(shapeEntity);
39 if (shapeEntitySource)
40 {
41 shapeEntitySource.Get("IsClosed", isShapeClosed);
42 if (SplineShapeEntity.Cast(shapeEntity) && isShapeClosed != shapeEntity.IsClosed()) // discrepancyyy
43 Print("Inverted \"Is Closed\" Spline tesselated points due to only having the shape's previous state!", LogLevel.WARNING);
44 }
45 }
46#endif // WORKBENCH
47
48 if (isShapeClosed)
49 {
50 anchorPoints.Insert(anchorPoints[0]);
51 ++anchorPointsCount;
52
53 if (!SplineShapeEntity.Cast(shapeEntity)) // spline already has the first tesselated point as last point
54 {
55 tesselatedPoints.Insert(tesselatedPoints[0]);
56 ++tesselatedPointsCount;
57 }
58 }
59
60 int anchorIndex;
61 vector anchorPos = anchorPoints[anchorIndex];
62 array<int> anchorIndices = {};
63 foreach (int i, vector tesselatedPoint : tesselatedPoints)
64 {
65 if (tesselatedPoint == anchorPos)
66 {
67 anchorIndices.Insert(i);
68 ++anchorIndex;
69 if (anchorIndex < anchorPointsCount)
70 anchorPos = anchorPoints[anchorIndex];
71 }
72 }
73
74 offsetTesselatedPoints.Copy(GetOffsetPointsFromPoints(tesselatedPoints, offset, yOffsetInShapeSpace, isShapeClosed));
75
76 offsetAnchorPoints.Clear();
77 foreach (int index : anchorIndices)
78 {
79 offsetAnchorPoints.Insert(offsetTesselatedPoints[index]);
80 }
81
82 if (offsetAnchorIndices)
83 offsetAnchorIndices.Copy(anchorIndices);
84
85 return true;
86 }
87
88 //------------------------------------------------------------------------------------------------
95 [Obsolete("This method taking a float offset is replaced with the vector one")] // obsolete since 2024-09-30
96 static bool GetAnchorsAndTesselatedPointsFromShape(notnull ShapeEntity shapeEntity, float xOffset, out notnull array<vector> offsetAnchorPoints, out notnull array<vector> offsetTesselatedPoints, out array<int> offsetAnchorIndices = null)
97 {
98 return GetAnchorsAndTesselatedPointsFromShape(shapeEntity, (vector){ xOffset, 0, 0 }, true, offsetAnchorPoints, offsetTesselatedPoints, offsetAnchorIndices);
99 }
100
101 //------------------------------------------------------------------------------------------------
107 static array<vector> GetRelativeOffsetPointsFromShape(notnull ShapeEntity shapeEntity, float offset, bool isShapeClosed)
108 {
109 array<vector> result = {};
110 shapeEntity.GenerateTesselatedShape(result);
111
112 if (offset != 0)
113 result = GetOffsetPointsFromPoints(result, offset, isShapeClosed);
114
115 return result;
116 }
117
118 //------------------------------------------------------------------------------------------------
124 static bool RemovePointsCloseToShape(notnull ShapeEntity shapeEntity, float deletionRadius, inout notnull array<vector> points)
125 {
126 if (deletionRadius <= 0)
127 return false;
128
130 for (int i = points.Count() - 1; i >= 0; --i)
131 {
132 if (shapeRuler.IsWithinDistance(points[i], deletionRadius, false))
133 points.RemoveOrdered(i);
134 }
135
136 return true;
137 }
138
139 //------------------------------------------------------------------------------------------------
145 static bool RemovePointsCloseToShapeXZ(notnull ShapeEntity shapeEntity, float deletionRadius, inout notnull array<vector> points)
146 {
147 if (deletionRadius <= 0)
148 return false;
149
150 int count = points.Count();
151 if (count < 1)
152 return false;
153
155 for (int i = count - 1; i >= 0; --i)
156 {
157 if (shapeRuler.IsWithinDistance(points[i], deletionRadius, false))
158 points.RemoveOrdered(i);
159 }
160
161 return true;
162 }
163
164 //------------------------------------------------------------------------------------------------
169 static bool SnapRelativePointsToGround(notnull ShapeEntity shapeEntity, inout notnull array<vector> points)
170 {
171 vector worldPos;
172 BaseWorld world = shapeEntity.GetWorld();
173 foreach (int i, vector point : points)
174 {
175 worldPos = shapeEntity.CoordToParent(point);
176 worldPos[1] = world.GetSurfaceY(worldPos[0], worldPos[2]);
177 points[i] = shapeEntity.CoordToLocal(worldPos);
178 }
179
180 return true;
181 }
182
183 //------------------------------------------------------------------------------------------------
188 static bool ReducePointsDensity(float minDistanceBetweenPoints, inout notnull array<vector> points)
189 {
190 int pointsCount = points.Count();
191 if (pointsCount < 3)
192 return false;
193
194 if (minDistanceBetweenPoints == 0)
195 return true;
196
197 float minDistanceBetweenPointsSq = minDistanceBetweenPoints * minDistanceBetweenPoints;
198
199 for (int i = pointsCount - 2; i >= 1; --i) // from count -1 to 1, avoiding first and last elements
200 {
201 if (vector.DistanceSq(points[i + 1], points[i]) < minDistanceBetweenPointsSq)
202 points.RemoveOrdered(i); // TODO: maybe a better filter like point average etc
203 else
204 if (i == 1 && vector.DistanceSq(points[0], points[1]) < minDistanceBetweenPointsSq)
205 points.RemoveOrdered(i);
206 }
207
208 return true;
209 }
210
211 //------------------------------------------------------------------------------------------------
216 static bool ReducePointsDensityXZ(float minDistanceBetweenPoints, inout notnull array<vector> points)
217 {
218 int pointsCount = points.Count();
219 if (pointsCount < 3)
220 return false;
221
222 float minDistanceBetweenPointsSq = minDistanceBetweenPoints * minDistanceBetweenPoints;
223
224 for (int i = pointsCount - 2; i >= 1; --i) // from count -1 to 1, avoiding first and last elements
225 {
226 if (vector.DistanceSqXZ(points[i + 1], points[i]) < minDistanceBetweenPointsSq)
227 points.RemoveOrdered(i); // TODO: maybe a better filter like point average etc
228 else
229 if (i == 1 && vector.DistanceSqXZ(points[0], points[1]) < minDistanceBetweenPointsSq)
230 points.RemoveOrdered(i);
231 }
232
233 return true;
234 }
235
236 //------------------------------------------------------------------------------------------------
242 static array<vector> GetOffsetPointsFromPoints(notnull array<vector> points, float offset, bool isShapeClosed)
243 {
244 return GetOffsetPointsFromPoints(points, (vector){ offset, 0, 0 }, true, isShapeClosed);
245 }
246
247 //------------------------------------------------------------------------------------------------
254 static array<vector> GetOffsetPointsFromPoints(notnull array<vector> points, vector offset, bool yOffsetInShapeSpace, bool isShapeClosed)
255 {
256 int count = points.Count();
257 if (count < 2)
258 return null;
259
260 if (offset == vector.Zero)
261 return SCR_ArrayHelperT<vector>.GetCopy(points);
262
263 return GetOffsetPointsFromRays(GetRaysFromPoints(points, isShapeClosed), offset, yOffsetInShapeSpace);
264 }
265
266 //------------------------------------------------------------------------------------------------
270 static array<ref SCR_Ray> GetRaysFromPoints(notnull array<vector> points, bool isShapeClosed)
271 {
272 int countMinus1 = points.Count() - 1;
273 if (countMinus1 < 1) // less than two points
274 return null;
275
276 array<ref SCR_Ray> result = {};
277 result.Reserve(countMinus1 + 1);
278
279 vector prevPoint;
280 SCR_Ray ray;
281 foreach (int i, vector currPoint : points)
282 {
283 ray = new SCR_Ray();
284 ray.m_vPosition = currPoint;
285
286 if (i == 0) // first point
287 {
288 if (isShapeClosed)
289 ray.m_vDirection = vector.Direction(points[countMinus1 - 1], points[1]);
290 else
291 ray.m_vDirection = vector.Direction(currPoint, points[1]);
292 }
293 else if (i < countMinus1) // middle point
294 {
295 ray.m_vDirection = vector.Direction(
296 vector.Direction(currPoint, prevPoint).Normalized(),
297 vector.Direction(currPoint, points[i + 1]).Normalized()
298 );
299 }
300 else // last point
301 {
302 if (isShapeClosed)
303 ray.m_vDirection = vector.Direction(prevPoint, points[1]);
304 else
305 ray.m_vDirection = vector.Direction(prevPoint, currPoint);
306 }
307
308 ray.m_vDirection.Normalize();
309 result.Insert(ray);
310
311 prevPoint = currPoint;
312 }
313
314 return result;
315 }
316
317 //------------------------------------------------------------------------------------------------
320 static void FlattenRays(inout notnull array<ref SCR_Ray> rays)
321 {
322 foreach (SCR_Ray ray : rays)
323 {
324 ray.m_vDirection[1] = 0;
325 ray.m_vDirection.Normalize();
326 }
327 }
328
329 //------------------------------------------------------------------------------------------------
333 static array<vector> GetOffsetPointsFromRays(notnull array<ref SCR_Ray> rays, float offset)
334 {
335 return GetOffsetPointsFromRays(rays, (vector){ offset, 0, 0 }, true);
336 }
337
338 //------------------------------------------------------------------------------------------------
343 static array<vector> GetOffsetPointsFromRays(notnull array<ref SCR_Ray> rays, vector offset, bool yOffsetInShapeSpace)
344 {
345 int countMinus1 = rays.Count() - 1;
346 if (countMinus1 < 0) // empty
347 return {};
348
349 if (countMinus1 < 1) // 1 element
350 return { GetOffsetPoint(rays[0].m_vPosition, rays[0].m_vDirection, offset, yOffsetInShapeSpace) };
351
352 vector prevNewPoint, currNewPoint;
353 SCR_Ray prevRay, nextRay;
354 array<vector> result = {};
355 result.Reserve(countMinus1 + 1);
356
357 foreach (int i, SCR_Ray currRay : rays)
358 {
359 if (i == 0 || i == countMinus1) // first or last
360 {
361 currNewPoint = GetOffsetPoint(currRay.m_vPosition, currRay.m_vDirection, offset, yOffsetInShapeSpace);
362 }
363 else // middle point
364 {
365 nextRay = rays[i + 1];
366
367 vector currRayOffsetPos = GetOffsetPoint(currRay.m_vPosition, currRay.m_vDirection, offset, yOffsetInShapeSpace);
368 vector nextRayOffsetPos = GetOffsetPoint(nextRay.m_vPosition, nextRay.m_vDirection, offset, yOffsetInShapeSpace);
369
370 float angleRad0 = SCR_Math2D.DegreeToTrigoRadian(vector.Direction(prevNewPoint, currRayOffsetPos).Normalized().ToYaw());
371 float angleRad1 = SCR_Math2D.DegreeToTrigoRadian(vector.Direction(nextRayOffsetPos, currRayOffsetPos).Normalized().ToYaw());
372
373 float x, z;
374 bool intersects = SCR_Math2D.GetLinesIntersectionXZ(
375 prevNewPoint[0], prevNewPoint[2], angleRad0,
376 nextRayOffsetPos[0], nextRayOffsetPos[2], angleRad1,
377 x, z);
378
379 if (intersects)
380 {
381 currNewPoint = { x, currRay.m_vPosition[1] + offset[1], z };
382 }
383 else // ALAAARM https://www.youtube.com/watch?v=hl8e9i6YiA8&t=52s - this should NEVER happen but hey, it does.
384 {
385 currNewPoint = vector.Lerp(prevNewPoint, nextRayOffsetPos, 0.5);
387 "[SCR_ParallelShapeHelper.GetOffsetPointsFromRays] does not intersect at point %1/%2 (most likely a straight line), using middle point %3 (%4 L%5)",
388 i, countMinus1 + 1, currNewPoint, __FILE__, __LINE__,
389 level: LogLevel.DEBUG);
390
392 "[SCR_ParallelShapeHelper.GetOffsetPointsFromRays] prev %1 at %2rad → %3 at %4rad next",
393 prevNewPoint, angleRad0.ToString(-1, 2),
394 nextRayOffsetPos, angleRad1.ToString(-1, 2),
395 level: LogLevel.DEBUG);
396 }
397 }
398
399 result.Insert(currNewPoint);
400
401 prevRay = currRay;
402 prevNewPoint = currNewPoint;
403 }
404
405 return result;
406 }
407
408 //------------------------------------------------------------------------------------------------
414 protected static vector GetOffsetPoint(vector position, vector direction, vector offset, bool yOffsetInShapeSpace)
415 {
416 vector mat[4];
417 if (yOffsetInShapeSpace)
418 {
419 direction[1] = 0;
420 direction.Normalize();
421 }
422
423 Math3D.DirectionAndUpMatrix(direction, vector.Up, mat);
424 return position + offset.Multiply4(mat);
425 }
426
427 //------------------------------------------------------------------------------------------------
428 // constructor - not available for creation
429 protected void SCR_ParallelShapeHelper();
430}
vector m_vPosition
vector direction
vector position
SCR_DestructionSynchronizationComponentClass ScriptComponentClass int index
static bool GetLinesIntersectionXZ(float x0, float y0, float angleRad0, float x1, float y1, float angleRad1, out float x, out float y)
Definition SCR_Math2D.c:342
static float DegreeToTrigoRadian(float value)
Definition SCR_Math2D.c:251
static vector GetOffsetPoint(vector position, vector direction, vector offset, bool yOffsetInShapeSpace)
bool IsWithinDistance(vector relativePos, float distance, bool equalCounts=true)
static SCR_ShapeDistanceRuler CreateFromShape(notnull ShapeEntity shapeEntity)
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 void PrintFormat(string fmt, void param1=NULL, void param2=NULL, void param3=NULL, void param4=NULL, void param5=NULL, void param6=NULL, void param7=NULL, void param8=NULL, void param9=NULL, LogLevel level=LogLevel.NORMAL)