Arma Reforger Explorer 1.7.0.54
Arma Reforger Code Explorer by Zeroy - Thanks to MisterOutofTime
Loading...
Searching...
No Matches
SCR_ShapeAnalyserEntity.c
Go to the documentation of this file.
1[EntityEditorProps(category: "GameScripted/Generators/Helpers", description: "", dynamicBox: true, visible: false)]
5
6class SCR_ShapeAnalyserEntity : SCR_GeneratorBaseEntity
7{
8 [Attribute(defvalue: "1", category: "Shape", desc: "")]
9 protected bool m_bDrawErrors;
10
11 [Attribute(defvalue: "30", category: "Shape", desc: "Maximum 2D angle (in degree) for a 10m line", params: "0 90 1", uiwidget: UIWidgets.Slider)]
12 protected float m_fMaxAngle;
13
14 [Attribute(defvalue: "10", category: "Shape", desc: "Maximum slope angle (in degree)", params: "0 90 1", uiwidget: UIWidgets.Slider)]
15 protected float m_fMaxSlope;
16
17 [Attribute(defvalue: "0", category: "Debug", desc: "")]
18 protected bool m_bDrawDebugShapes;
19
20 [Attribute(defvalue: "0", category: "Debug", desc: "")]
21 protected bool m_bPrintDebugInfo;
22
23#ifdef WORKBENCH
24
25 protected static ref array<ref Shape> s_aErrorShapes;
26 protected static ref array<ref Shape> s_aDebugShapes;
27
28 protected static const int ERROR_SHAPE_ANGLE_ARRAY_LENGTH = 50;
29 protected static const float ERROR_SHAPE_ANGLE_CHECK_LENGTH = 10.0;
30
31 protected static float SLOPE_ERROR_SHAPE_LENGTH = 30.0;
32 protected static float ANGLE_ERROR_LINE_LENGTH = 5.0;
33
34 protected static vector NORMAL_POINT_LINE_VECTOR = "0 20 0";
35 protected static float NORMAL_POINT_LINE_HAT_SIZE = 1.0;
36 protected static vector TESSELATED_POINT_LINE_VECTOR = "0 10 0";
37 protected static vector MIDDLE_POINT_LINE_VECTOR = "0 15 0";
38 protected static int ERROR_SHAPE_COLOUR = Color.RED;
39 protected static int DEBUG_SHAPE_COLOUR = Color.MAGENTA;
40 protected static int DEBUG_SHAPE_COLOUR_IMPORTANT = Color.DARK_RED;
41 protected static ShapeFlags DEBUG_SHAPE_FLAGS = ShapeFlags.NOZBUFFER;
42 protected static ShapeFlags DEBUG_SHAPE_FLAGS_SPHERE = ShapeFlags.NOOUTLINE | ShapeFlags.TRANSP;
43 protected static int DEBUG_SHAPE_COLOUR_ALPHA = 0x66000000;
44
45
46 //------------------------------------------------------------------------------------------------
47 override bool _WB_OnKeyChanged(BaseContainer src, string key, BaseContainerList ownerContainers, IEntity parent)
48 {
49 if (!super._WB_OnKeyChanged(src, key, ownerContainers, parent))
50 return false;
51
52 if (!m_ParentShapeSource)
53 return false;
54
55 WorldEditorAPI worldEditorAPI = _WB_GetEditorAPI();
56 if (!worldEditorAPI || worldEditorAPI.UndoOrRedoIsRestoring())
57 return false;
58
59 ShapeEntity parentShape = ShapeEntity.Cast(worldEditorAPI.SourceToEntity(m_ParentShapeSource));
60 if (!parentShape)
61 return false;
62
63 src = worldEditorAPI.EntityToSource(this);
64 BaseContainerTools.WriteToInstance(this, src); // refresh attributes
65
66 Process(m_ParentShapeSource, parentShape);
67
68 return true;
69 }
70
71 //------------------------------------------------------------------------------------------------
72 protected override void OnShapeChangedInternal(IEntitySource shapeEntitySrc, ShapeEntity shapeEntity, array<vector> mins, array<vector> maxes)
73 {
74 super.OnShapeChangedInternal(shapeEntitySrc, shapeEntity, mins, maxes);
75
76 WorldEditorAPI worldEditorAPI = _WB_GetEditorAPI();
77 if (worldEditorAPI)
78 return;
79
80 shapeEntity = ShapeEntity.Cast(worldEditorAPI.SourceToEntity(m_ParentShapeSource));
81
82 Process(shapeEntitySrc, shapeEntity);
83 }
84
85 //------------------------------------------------------------------------------------------------
86 protected void Process(notnull IEntitySource shapeEntitySrc, notnull ShapeEntity shapeEntity)
87 {
88 SCR_ShapeAnalyser shapeAnalyser = SCR_ShapeAnalyser.CreateFromShape(shapeEntity);
89
90 s_aDebugShapes = null;
91 s_aErrorShapes = null;
92
94 DrawDebugShapes(shapeAnalyser);
95
96 if (m_bDrawErrors)
97 DrawErrorShapes(shapeAnalyser);
98
99 if (m_bPrintDebugInfo)
100 PrintDebugInfo(shapeAnalyser);
101 }
102
103 //------------------------------------------------------------------------------------------------
104 protected void DrawDebugShapes(notnull SCR_ShapeAnalyser shapeAnalyser)
105 {
106 s_aDebugShapes = {};
107
108 array<ref SCR_Ray> pointRays = shapeAnalyser.GetAbsoluteAnchorPointRays();
109 array<ref SCR_Ray> middlePointRays = shapeAnalyser.GetAbsoluteMiddlePointRays();
110 array<ref SCR_Ray> tesselatedPointRays = shapeAnalyser.GetAbsoluteTesselatedPointRays();
111
112 int currentPointIndex = 0;
113 int currentMiddlePointIndex = 0;
114 int lastPointIndex = pointRays.Count() - 1;
115 int lastMiddlePointIndex = pointRays.Count() - 1;
116 SCR_Ray currentPoint = pointRays[0];
117 SCR_Ray currentMiddlePoint = middlePointRays[0];
118
119 foreach (SCR_Ray pointRay : tesselatedPointRays)
120 {
121 if (pointRay == currentPoint)
122 {
123 AddDebugLine(pointRay.m_vPosition, pointRay.m_vPosition + NORMAL_POINT_LINE_VECTOR, true);
124 AddDebugLine(pointRay.m_vPosition - pointRay.m_vDirection * NORMAL_POINT_LINE_VECTOR[1], pointRay.m_vPosition + pointRay.m_vDirection * NORMAL_POINT_LINE_VECTOR[1], true);
125 currentPointIndex++;
126 if (currentPointIndex < lastPointIndex)
127 currentPoint = pointRays[currentPointIndex];
128 }
129 else if (pointRay == currentMiddlePoint)
130 {
131 AddDebugLine(pointRay.m_vPosition, pointRay.m_vPosition + MIDDLE_POINT_LINE_VECTOR, true);
132 AddDebugLine(pointRay.m_vPosition - pointRay.m_vDirection * MIDDLE_POINT_LINE_VECTOR[1], pointRay.m_vPosition + pointRay.m_vDirection * MIDDLE_POINT_LINE_VECTOR[1], true);
133 currentMiddlePointIndex++;
134 if (currentMiddlePointIndex < lastMiddlePointIndex)
135 currentMiddlePoint = middlePointRays[currentMiddlePointIndex];
136 }
137 else // normal
138 {
139 AddDebugLine(pointRay.m_vPosition, pointRay.m_vPosition + TESSELATED_POINT_LINE_VECTOR);
140 }
141 }
142 }
143
144 //------------------------------------------------------------------------------------------------
145 protected void AddDebugLine(vector pointA, vector pointB, bool isImportant = false)
146 {
147 vector pointRays[2] = { pointA, pointB };
148 if (isImportant)
149 s_aDebugShapes.Insert(Shape.CreateLines(DEBUG_SHAPE_COLOUR_IMPORTANT, DEBUG_SHAPE_FLAGS, pointRays, 2));
150 else
151 s_aDebugShapes.Insert(Shape.CreateLines(DEBUG_SHAPE_COLOUR, DEBUG_SHAPE_FLAGS, pointRays, 2));
152 }
153
154 //------------------------------------------------------------------------------------------------
155 protected void DrawErrorShapes(notnull SCR_ShapeAnalyser shapeAnalyser)
156 {
157 array<ref SCR_Ray> pointRays = shapeAnalyser.GetAbsoluteAnchorPointRays();
158 array<ref SCR_Ray> tesselatedPointRays = shapeAnalyser.GetAbsoluteTesselatedPointRays();
159
160 // error display
161 s_aErrorShapes = {};
162 vector segment[2];
163
164 float firstAngleDeg = Math.Atan2(pointRays[0].m_vDirection[0], pointRays[0].m_vDirection[2]) * Math.RAD2DEG;
165 float lastAnglesDeg[ERROR_SHAPE_ANGLE_ARRAY_LENGTH];
166 float lastAnglesDist[ERROR_SHAPE_ANGLE_ARRAY_LENGTH];
167 for (int i; i < ERROR_SHAPE_ANGLE_ARRAY_LENGTH; i++)
168 {
169 lastAnglesDeg[i] = firstAngleDeg;
170 }
171
172 int lastTesselatedIndex = tesselatedPointRays.Count() - 1;
173
174 foreach (int i, SCR_Ray tesselatedPoint : tesselatedPointRays)
175 {
176 // too slopy!
177 float slopeDeg = Math.Atan2(tesselatedPoint.m_vDirection[1], vector.DistanceXZ(tesselatedPoint.m_vDirection, vector.Zero)) * Math.RAD2DEG;
178 if (slopeDeg > m_fMaxSlope || slopeDeg < -m_fMaxSlope)
179 {
180 segment[0] = tesselatedPoint.m_vPosition;
181 segment[1] = segment[0] + vector.Up * SLOPE_ERROR_SHAPE_LENGTH;
182 s_aErrorShapes.Insert(Shape.CreateLines(Color.RED, ShapeFlags.NOZBUFFER, segment, 2));
183 }
184
185 // too tight turn!
186 float angleDeg = Math.Atan2(tesselatedPoint.m_vDirection[0], tesselatedPoint.m_vDirection[2]) * Math.RAD2DEG;
187 float angleRad = Math.Atan2(tesselatedPoint.m_vDirection[2], tesselatedPoint.m_vDirection[0]);
188
189 float totalDist;
190 for (int j = ERROR_SHAPE_ANGLE_ARRAY_LENGTH - 1; j >= 0; j--) // last to first!
191 {
192 if (lastAnglesDist[j] == 0)
193 break;
194
195 float angleDiffDeg = lastAnglesDeg[j] - angleDeg;
196
197 if (angleDiffDeg <= -180 || angleDiffDeg > 180)
198 angleDiffDeg = Math.Repeat(180 + angleDiffDeg, 360) - 180;
199
200 if (angleDiffDeg < 0)
201 angleDiffDeg *= -1;
202
203 if (angleDiffDeg > m_fMaxAngle)
204 {
205 segment[0] = tesselatedPoint.m_vPosition + { Math.Cos(angleRad - Math.PI_HALF), 0, Math.Sin(angleRad - Math.PI_HALF) } * (ANGLE_ERROR_LINE_LENGTH * 0.5);
206 segment[1] = tesselatedPoint.m_vPosition + { Math.Cos(angleRad + Math.PI_HALF), 0, Math.Sin(angleRad + Math.PI_HALF) } * (ANGLE_ERROR_LINE_LENGTH * 0.5);
207 s_aErrorShapes.Insert(Shape.CreateLines(Color.RED, ShapeFlags.NOZBUFFER, segment, 2));
208 break;
209 }
210
211 totalDist += lastAnglesDist[j];
212 if (totalDist > ERROR_SHAPE_ANGLE_CHECK_LENGTH)
213 break;
214 }
215
216 // shift everything back by one
217 for (int j, jMax = ERROR_SHAPE_ANGLE_ARRAY_LENGTH - 1; j < jMax; j++)
218 {
219 lastAnglesDeg[j] = lastAnglesDeg[j + 1];
220 lastAnglesDist[j] = lastAnglesDist[j + 1];
221 }
222
223 lastAnglesDeg[ERROR_SHAPE_ANGLE_ARRAY_LENGTH - 1] = angleDeg;
224 if (i != lastTesselatedIndex)
225 lastAnglesDist[ERROR_SHAPE_ANGLE_ARRAY_LENGTH - 1] = vector.DistanceXZ(tesselatedPoint.m_vPosition, tesselatedPointRays[i + 1].m_vPosition);
226 }
227
228 }
229
230 //------------------------------------------------------------------------------------------------
231 protected void PrintDebugInfo(notnull SCR_ShapeAnalyser shapeAnalyser)
232 {
233 array<ref SCR_Ray> pointRays = shapeAnalyser.GetAbsoluteAnchorPointRays();
234 array<ref SCR_Ray> tesselatedPointRays = shapeAnalyser.GetAbsoluteTesselatedPointRays();
235 array<float> polygon2D = {};
236
237 array<float> stats = shapeAnalyser.GetStats();
238
239 int statIndex;
240 float length2D = stats[statIndex++];
241 float length3D = stats[statIndex++];
242 float surface = stats[statIndex++];
243 float minAlt = stats[statIndex++], maxAlt = stats[statIndex++];
244 float minSlope = stats[statIndex++], maxSlope = stats[statIndex++];
245
246 float minAltATL = float.INFINITY, maxAltATL = -float.INFINITY;
247
248 SCR_Ray prevPointRay;
249 foreach (int i, SCR_Ray pointRay : tesselatedPointRays)
250 {
251 if (prevPointRay)
252 {
253 length2D += vector.DistanceXZ(prevPointRay.m_vPosition, pointRay.m_vPosition);
254 length3D += vector.Distance(prevPointRay.m_vPosition, pointRay.m_vPosition);
255 }
256
257 float tmp = pointRay.m_vPosition[1] - GetWorld().GetSurfaceY(pointRay.m_vPosition[0], pointRay.m_vPosition[2]);
258
259 if (tmp < minAltATL)
260 minAltATL = tmp;
261
262 if (tmp > maxAltATL)
263 maxAltATL = tmp;
264
265 prevPointRay = pointRay;
266 }
267
268 Print(string.Format("%1 pointRays, %2 tesselated pointRays", pointRays.Count(), tesselatedPointRays.Count()), LogLevel.NORMAL);
269 Print("Length 2D/3D : " + length2D.ToString(lenDec: 2) + "m / " + length3D.ToString(lenDec: 2) + "m", LogLevel.NORMAL);
270
271 if (shapeAnalyser.IsClosed())
272 Print("Surface area : " + SCR_Math2D.GetPolygonArea(polygon2D).ToString(lenDec: 2) + "m sq.", LogLevel.NORMAL);
273 else
274 Print("Surface area : not an area", LogLevel.NORMAL);
275
276 Print("Min/Max slope : [" + (minSlope * Math.RAD2DEG).ToString(lenDec: 2) + "deg / " + (maxSlope * Math.RAD2DEG).ToString(lenDec: 2) + "deg]", LogLevel.NORMAL);
277 Print("Min/Max altitude : [" + minAlt.ToString(lenDec: 2) + "m / " + maxAlt.ToString(lenDec: 2) + "m]", LogLevel.NORMAL);
278 Print("Min/Max alt ATL : [" + minAltATL.ToString(lenDec: 2) + "m / " + maxAltATL.ToString(lenDec: 2) + "m]", LogLevel.NORMAL);
279 }
280
281#endif // WORKBENCH
282
283}
bool m_bDrawDebugShapes
enum SCR_ECompassType EntityEditorProps(category:"GameScripted/Gadgets", description:"Compass", color:"0 0 255 255")
Prefab data class for compass component.
override bool _WB_OnKeyChanged(IEntity owner, BaseContainer src, string key, BaseContainerList ownerContainers, IEntity parent)
Any property value has been changed. You can use editor API here and do some additional edit actions ...
UI Textures DeployMenu Briefing conflict_HintBanner_1_UI desc
Definition Color.c:13
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
ShapeFlags
Definition ShapeFlags.c:13
SCR_FieldOfViewSettings Attribute
void OnShapeChangedInternal(IEntitySource shapeEntitySrc, ShapeEntity shapeEntity, array< vector > mins, array< vector > maxes)