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)
13 if (!offsetAnchorPoints && !offsetTesselatedPoints && !offsetAnchorIndices)
16 array<vector> anchorPoints = {};
17 shapeEntity.GetPointsPositions(anchorPoints);
18 int anchorPointsCount = anchorPoints.Count();
19 if (anchorPointsCount < 2)
23 array<vector> tesselatedPoints = {};
24 shapeEntity.GenerateTesselatedShape(tesselatedPoints);
25 int tesselatedPointsCount = tesselatedPoints.Count();
26 if (tesselatedPointsCount < anchorPointsCount)
29 if (anchorPoints[0] != tesselatedPoints[0])
32 bool isShapeClosed = shapeEntity.IsClosed();
35 WorldEditorAPI worldEditorAPI = ((WorldEditor)Workbench.GetModule(WorldEditor)).GetApi();
38 IEntitySource shapeEntitySource = worldEditorAPI.EntityToSource(shapeEntity);
39 if (shapeEntitySource)
41 shapeEntitySource.Get(
"IsClosed", isShapeClosed);
42 if (SplineShapeEntity.Cast(shapeEntity) && isShapeClosed != shapeEntity.IsClosed())
43 Print(
"Inverted \"Is Closed\" Spline tesselated points due to only having the shape's previous state!",
LogLevel.WARNING);
50 anchorPoints.Insert(anchorPoints[0]);
53 if (!SplineShapeEntity.Cast(shapeEntity))
55 tesselatedPoints.Insert(tesselatedPoints[0]);
56 ++tesselatedPointsCount;
61 vector anchorPos = anchorPoints[anchorIndex];
62 array<int> anchorIndices = {};
63 foreach (
int i,
vector tesselatedPoint : tesselatedPoints)
65 if (tesselatedPoint == anchorPos)
67 anchorIndices.Insert(i);
69 if (anchorIndex < anchorPointsCount)
70 anchorPos = anchorPoints[anchorIndex];
74 offsetTesselatedPoints.Copy(GetOffsetPointsFromPoints(tesselatedPoints, offset, yOffsetInShapeSpace, isShapeClosed));
76 offsetAnchorPoints.Clear();
77 foreach (
int index : anchorIndices)
79 offsetAnchorPoints.Insert(offsetTesselatedPoints[
index]);
82 if (offsetAnchorIndices)
83 offsetAnchorIndices.Copy(anchorIndices);
95 [
Obsolete(
"This method taking a float offset is replaced with the vector one")]
96 static bool GetAnchorsAndTesselatedPointsFromShape(notnull ShapeEntity shapeEntity,
float xOffset, out notnull array<vector> offsetAnchorPoints, out notnull array<vector> offsetTesselatedPoints, out array<int> offsetAnchorIndices = null)
98 return GetAnchorsAndTesselatedPointsFromShape(shapeEntity, (
vector){ xOffset, 0, 0 },
true, offsetAnchorPoints, offsetTesselatedPoints, offsetAnchorIndices);
107 static array<vector> GetRelativeOffsetPointsFromShape(notnull ShapeEntity shapeEntity,
float offset,
bool isShapeClosed)
109 array<vector> result = {};
110 shapeEntity.GenerateTesselatedShape(result);
113 result = GetOffsetPointsFromPoints(result, offset, isShapeClosed);
124 static bool RemovePointsCloseToShape(notnull ShapeEntity shapeEntity,
float deletionRadius, inout notnull array<vector> points)
126 if (deletionRadius <= 0)
130 for (
int i = points.Count() - 1; i >= 0; --i)
133 points.RemoveOrdered(i);
145 static bool RemovePointsCloseToShapeXZ(notnull ShapeEntity shapeEntity,
float deletionRadius, inout notnull array<vector> points)
147 if (deletionRadius <= 0)
150 int count = points.Count();
155 for (
int i = count - 1; i >= 0; --i)
158 points.RemoveOrdered(i);
169 static bool SnapRelativePointsToGround(notnull ShapeEntity shapeEntity, inout notnull array<vector> points)
172 BaseWorld world = shapeEntity.GetWorld();
173 foreach (
int i,
vector point : points)
175 worldPos = shapeEntity.CoordToParent(point);
176 worldPos[1] = world.GetSurfaceY(worldPos[0], worldPos[2]);
177 points[i] = shapeEntity.CoordToLocal(worldPos);
188 static bool ReducePointsDensity(
float minDistanceBetweenPoints, inout notnull array<vector> points)
190 int pointsCount = points.Count();
194 if (minDistanceBetweenPoints == 0)
197 float minDistanceBetweenPointsSq = minDistanceBetweenPoints * minDistanceBetweenPoints;
199 for (
int i = pointsCount - 2; i >= 1; --i)
201 if (
vector.DistanceSq(points[i + 1], points[i]) < minDistanceBetweenPointsSq)
202 points.RemoveOrdered(i);
204 if (i == 1 &&
vector.DistanceSq(points[0], points[1]) < minDistanceBetweenPointsSq)
205 points.RemoveOrdered(i);
216 static bool ReducePointsDensityXZ(
float minDistanceBetweenPoints, inout notnull array<vector> points)
218 int pointsCount = points.Count();
222 float minDistanceBetweenPointsSq = minDistanceBetweenPoints * minDistanceBetweenPoints;
224 for (
int i = pointsCount - 2; i >= 1; --i)
226 if (
vector.DistanceSqXZ(points[i + 1], points[i]) < minDistanceBetweenPointsSq)
227 points.RemoveOrdered(i);
229 if (i == 1 &&
vector.DistanceSqXZ(points[0], points[1]) < minDistanceBetweenPointsSq)
230 points.RemoveOrdered(i);
242 static array<vector> GetOffsetPointsFromPoints(notnull array<vector> points,
float offset,
bool isShapeClosed)
244 return GetOffsetPointsFromPoints(points, (
vector){ offset, 0, 0 },
true, isShapeClosed);
254 static array<vector> GetOffsetPointsFromPoints(notnull array<vector> points,
vector offset,
bool yOffsetInShapeSpace,
bool isShapeClosed)
256 int count = points.Count();
260 if (offset ==
vector.Zero)
261 return SCR_ArrayHelperT<vector>.GetCopy(points);
263 return GetOffsetPointsFromRays(GetRaysFromPoints(points, isShapeClosed), offset, yOffsetInShapeSpace);
270 static array<ref SCR_Ray> GetRaysFromPoints(notnull array<vector> points,
bool isShapeClosed)
272 int countMinus1 = points.Count() - 1;
276 array<ref SCR_Ray> result = {};
277 result.Reserve(countMinus1 + 1);
281 foreach (
int i,
vector currPoint : points)
284 ray.m_vPosition = currPoint;
289 ray.m_vDirection =
vector.Direction(points[countMinus1 - 1], points[1]);
291 ray.m_vDirection =
vector.Direction(currPoint, points[1]);
293 else if (i < countMinus1)
295 ray.m_vDirection =
vector.Direction(
296 vector.Direction(currPoint, prevPoint).Normalized(),
297 vector.Direction(currPoint, points[i + 1]).Normalized()
303 ray.m_vDirection =
vector.Direction(prevPoint, points[1]);
305 ray.m_vDirection =
vector.Direction(prevPoint, currPoint);
308 ray.m_vDirection.Normalize();
311 prevPoint = currPoint;
320 static void FlattenRays(inout notnull array<ref SCR_Ray> rays)
324 ray.m_vDirection[1] = 0;
325 ray.m_vDirection.Normalize();
333 static array<vector> GetOffsetPointsFromRays(notnull array<ref SCR_Ray> rays,
float offset)
335 return GetOffsetPointsFromRays(rays, (
vector){ offset, 0, 0 },
true);
343 static array<vector> GetOffsetPointsFromRays(notnull array<ref SCR_Ray> rays,
vector offset,
bool yOffsetInShapeSpace)
345 int countMinus1 = rays.Count() - 1;
352 vector prevNewPoint, currNewPoint;
354 array<vector> result = {};
355 result.Reserve(countMinus1 + 1);
357 foreach (
int i,
SCR_Ray currRay : rays)
359 if (i == 0 || i == countMinus1)
361 currNewPoint =
GetOffsetPoint(currRay.m_vPosition, currRay.m_vDirection, offset, yOffsetInShapeSpace);
365 nextRay = rays[i + 1];
367 vector currRayOffsetPos =
GetOffsetPoint(currRay.m_vPosition, currRay.m_vDirection, offset, yOffsetInShapeSpace);
368 vector nextRayOffsetPos =
GetOffsetPoint(nextRay.m_vPosition, nextRay.m_vDirection, offset, yOffsetInShapeSpace);
375 prevNewPoint[0], prevNewPoint[2], angleRad0,
376 nextRayOffsetPos[0], nextRayOffsetPos[2], angleRad1,
381 currNewPoint = { x, currRay.m_vPosition[1] + offset[1], z };
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__,
392 "[SCR_ParallelShapeHelper.GetOffsetPointsFromRays] prev %1 at %2rad → %3 at %4rad next",
393 prevNewPoint, angleRad0.ToString(-1, 2),
394 nextRayOffsetPos, angleRad1.ToString(-1, 2),
399 result.Insert(currNewPoint);
402 prevNewPoint = currNewPoint;
417 if (yOffsetInShapeSpace)
424 return position + offset.Multiply4(mat);