Arma Reforger Explorer  1.1.0.42
Arma Reforger Code Explorer by Zeroy - Thanks to MisterOutofTime
SCR_ShapeAnalyserEntity.c
Go to the documentation of this file.
1 [EntityEditorProps(category: "GameLib/Scripted", description: "", dynamicBox: true, visible: false)]
2 class SCR_ShapeAnalyserEntityClass : /*SCR_*/GeneratorBaseEntityClass
3 {
4 }
5 
6 class 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  bool parentResult = super._WB_OnKeyChanged(src, key, ownerContainers, parent);
50 
51  if (!parent)
52  return parentResult;
53 
54  ShapeEntity parentShape = ShapeEntity.Cast(parent);
55  if (!parentShape)
56  return parentResult;
57 
58  WorldEditorAPI worldEditorAPI = _WB_GetEditorAPI();
59  if (!worldEditorAPI)
60  return parentResult;
61 
62  src = worldEditorAPI.EntityToSource(this);
63  BaseContainerTools.WriteToInstance(this, src); // refresh attributes
64 
65  Process(worldEditorAPI.EntityToSource(parent), parentShape);
66 
67  return true;
68  }
69 
70  //------------------------------------------------------------------------------------------------
71  protected override void OnShapeChangedInternal(IEntitySource shapeEntitySrc, ShapeEntity shapeEntity, array<vector> mins, array<vector> maxes)
72  {
73  super.OnShapeChangedInternal(shapeEntitySrc, shapeEntity, mins, maxes);
74 
75  Process(shapeEntitySrc, shapeEntity);
76  }
77 
78  //------------------------------------------------------------------------------------------------
79  protected void Process(notnull IEntitySource shapeEntitySrc, notnull ShapeEntity shapeEntity)
80  {
81  bool isClosed;
82  SCR_ShapeAnalyser shapeAnalyser = new SCR_ShapeAnalyser(shapeEntity, shapeEntitySrc.Get("IsClosed", isClosed) && isClosed);
83 
84  s_aDebugShapes = null;
85  s_aErrorShapes = null;
86 
87  if (m_bDrawDebugShapes)
88  DrawDebugShapes(shapeAnalyser);
89 
90  if (m_bDrawErrors)
91  DrawErrorShapes(shapeAnalyser);
92 
93  if (m_bPrintDebugInfo)
94  PrintDebugInfo(shapeAnalyser);
95  }
96 
97  //------------------------------------------------------------------------------------------------
98  protected void DrawDebugShapes(notnull SCR_ShapeAnalyser shapeAnalyser)
99  {
100  s_aDebugShapes = {};
101 
102  array<ref SCR_Ray> pointRays = shapeAnalyser.GetPoints();
103  array<ref SCR_Ray> middlePointRays = shapeAnalyser.GetMiddlePoints();
104  array<ref SCR_Ray> tesselatedPointRays = shapeAnalyser.GetTesselatedPoints();
105 
106  int currentPointIndex = 0;
107  int currentMiddlePointIndex = 0;
108  int lastPointIndex = pointRays.Count() - 1;
109  int lastMiddlePointIndex = pointRays.Count() - 1;
110  SCR_Ray currentPoint = pointRays[0];
111  SCR_Ray currentMiddlePoint = middlePointRays[0];
112 
113  foreach (SCR_Ray pointRay : tesselatedPointRays)
114  {
115  if (pointRay == currentPoint)
116  {
117  AddDebugLine(pointRay.m_vPosition, pointRay.m_vPosition + NORMAL_POINT_LINE_VECTOR, true);
118  AddDebugLine(pointRay.m_vPosition - pointRay.m_vDirection * NORMAL_POINT_LINE_VECTOR[1], pointRay.m_vPosition + pointRay.m_vDirection * NORMAL_POINT_LINE_VECTOR[1], true);
119  currentPointIndex++;
120  if (currentPointIndex < lastPointIndex)
121  currentPoint = pointRays[currentPointIndex];
122  }
123  else if (pointRay == currentMiddlePoint)
124  {
125  AddDebugLine(pointRay.m_vPosition, pointRay.m_vPosition + MIDDLE_POINT_LINE_VECTOR, true);
126  AddDebugLine(pointRay.m_vPosition - pointRay.m_vDirection * MIDDLE_POINT_LINE_VECTOR[1], pointRay.m_vPosition + pointRay.m_vDirection * MIDDLE_POINT_LINE_VECTOR[1], true);
127  currentMiddlePointIndex++;
128  if (currentMiddlePointIndex < lastMiddlePointIndex)
129  currentMiddlePoint = middlePointRays[currentMiddlePointIndex];
130  }
131  else // normal
132  {
133  AddDebugLine(pointRay.m_vPosition, pointRay.m_vPosition + TESSELATED_POINT_LINE_VECTOR);
134  }
135  }
136  }
137 
138  //------------------------------------------------------------------------------------------------
139  protected void AddDebugLine(vector pointA, vector pointB, bool isImportant = false)
140  {
141  vector pointRays[2] = { pointA, pointB };
142  if (isImportant)
143  s_aDebugShapes.Insert(Shape.CreateLines(DEBUG_SHAPE_COLOUR_IMPORTANT, DEBUG_SHAPE_FLAGS, pointRays, 2));
144  else
145  s_aDebugShapes.Insert(Shape.CreateLines(DEBUG_SHAPE_COLOUR, DEBUG_SHAPE_FLAGS, pointRays, 2));
146  }
147 
148  //------------------------------------------------------------------------------------------------
149  protected void DrawErrorShapes(notnull SCR_ShapeAnalyser shapeAnalyser)
150  {
151  array<ref SCR_Ray> pointRays = shapeAnalyser.GetPoints();
152  array<ref SCR_Ray> tesselatedPointRays = shapeAnalyser.GetTesselatedPoints();
153 
154  // error display
155  s_aErrorShapes = {};
156  vector segment[2];
157 
158  float firstAngleDeg = Math.Atan2(pointRays[0].m_vDirection[0], pointRays[0].m_vDirection[2]) * Math.RAD2DEG;
159  float lastAnglesDeg[ERROR_SHAPE_ANGLE_ARRAY_LENGTH];
160  float lastAnglesDist[ERROR_SHAPE_ANGLE_ARRAY_LENGTH];
161  for (int i; i < ERROR_SHAPE_ANGLE_ARRAY_LENGTH; i++)
162  {
163  lastAnglesDeg[i] = firstAngleDeg;
164  }
165 
166  int lastTesselatedIndex = tesselatedPointRays.Count() - 1;
167 
168  foreach (int i, SCR_Ray tesselatedPoint : tesselatedPointRays)
169  {
170  // too slopy!
171  float slopeDeg = Math.Atan2(tesselatedPoint.m_vDirection[1], vector.DistanceXZ(tesselatedPoint.m_vDirection, vector.Zero)) * Math.RAD2DEG;
172  if (slopeDeg > m_fMaxSlope || slopeDeg < -m_fMaxSlope)
173  {
174  segment[0] = tesselatedPoint.m_vPosition;
175  segment[1] = segment[0] + vector.Up * SLOPE_ERROR_SHAPE_LENGTH;
176  s_aErrorShapes.Insert(Shape.CreateLines(Color.RED, ShapeFlags.NOZBUFFER, segment, 2));
177  }
178 
179  // too tight turn!
180  float angleDeg = Math.Atan2(tesselatedPoint.m_vDirection[0], tesselatedPoint.m_vDirection[2]) * Math.RAD2DEG;
181  float angleRad = Math.Atan2(tesselatedPoint.m_vDirection[2], tesselatedPoint.m_vDirection[0]);
182 
183  float totalDist;
184  for (int j = ERROR_SHAPE_ANGLE_ARRAY_LENGTH - 1; j >= 0; j--) // last to first!
185  {
186  if (lastAnglesDist[j] == 0)
187  break;
188 
189  float angleDiffDeg = lastAnglesDeg[j] - angleDeg;
190 
191  if (angleDiffDeg <= -180 || angleDiffDeg > 180)
192  angleDiffDeg = Math.Repeat(180 + angleDiffDeg, 360) - 180;
193 
194  if (angleDiffDeg < 0)
195  angleDiffDeg *= -1;
196 
197  if (angleDiffDeg > m_fMaxAngle)
198  {
199  segment[0] = tesselatedPoint.m_vPosition + { Math.Cos(angleRad - Math.PI_HALF), 0, Math.Sin(angleRad - Math.PI_HALF) } * (ANGLE_ERROR_LINE_LENGTH * 0.5);
200  segment[1] = tesselatedPoint.m_vPosition + { Math.Cos(angleRad + Math.PI_HALF), 0, Math.Sin(angleRad + Math.PI_HALF) } * (ANGLE_ERROR_LINE_LENGTH * 0.5);
201  s_aErrorShapes.Insert(Shape.CreateLines(Color.RED, ShapeFlags.NOZBUFFER, segment, 2));
202  break;
203  }
204 
205  totalDist += lastAnglesDist[j];
206  if (totalDist > ERROR_SHAPE_ANGLE_CHECK_LENGTH)
207  break;
208  }
209 
210  // shift everything back by one
211  for (int j, jMax = ERROR_SHAPE_ANGLE_ARRAY_LENGTH - 1; j < jMax; j++)
212  {
213  lastAnglesDeg[j] = lastAnglesDeg[j + 1];
214  lastAnglesDist[j] = lastAnglesDist[j + 1];
215  }
216 
217  lastAnglesDeg[ERROR_SHAPE_ANGLE_ARRAY_LENGTH - 1] = angleDeg;
218  if (i != lastTesselatedIndex)
219  lastAnglesDist[ERROR_SHAPE_ANGLE_ARRAY_LENGTH - 1] = vector.DistanceXZ(tesselatedPoint.m_vPosition, tesselatedPointRays[i + 1].m_vPosition);
220  }
221 
222  }
223 
224  //------------------------------------------------------------------------------------------------
225  protected void PrintDebugInfo(notnull SCR_ShapeAnalyser shapeAnalyser)
226  {
227  array<ref SCR_Ray> pointRays = shapeAnalyser.GetPoints();
228  array<ref SCR_Ray> tesselatedPointRays = shapeAnalyser.GetTesselatedPoints();
229  array<float> polygon2D = {};
230 
231  array<float> stats = shapeAnalyser.GetStats();
232 
233  int statIndex;
234  float length2D = stats[statIndex++];
235  float length3D = stats[statIndex++];
236  float surface = stats[statIndex++];
237  float minAlt = stats[statIndex++], maxAlt = stats[statIndex++];
238  float minSlope = stats[statIndex++], maxSlope = stats[statIndex++];
239 
240  float minAltATL = float.INFINITY, maxAltATL = -float.INFINITY;
241 
242  float tmp;
243  SCR_Ray prevPointRay;
244  foreach (int i, SCR_Ray pointRay : tesselatedPointRays)
245  {
246  if (prevPointRay)
247  {
248  length2D += vector.DistanceXZ(prevPointRay.m_vPosition, pointRay.m_vPosition);
249  length3D += vector.Distance(prevPointRay.m_vPosition, pointRay.m_vPosition);
250  }
251 
252  tmp = pointRay.m_vPosition[1] - GetWorld().GetSurfaceY(pointRay.m_vPosition[0], pointRay.m_vPosition[2]);
253 
254  if (tmp < minAltATL)
255  minAltATL = tmp;
256 
257  if (tmp > maxAltATL)
258  maxAltATL = tmp;
259 
260  prevPointRay = pointRay;
261  }
262 
263  Print(string.Format("%1 pointRays, %2 tesselated pointRays", pointRays.Count(), tesselatedPointRays.Count()), LogLevel.NORMAL);
264  Print("Length 2D/3D : " + length2D.ToString(lenDec: 2) + "m / " + length3D.ToString(lenDec: 2) + "m", LogLevel.NORMAL);
265 
266  if (shapeAnalyser.IsClosed())
267  Print("Surface area : " + SCR_Math2D.GetPolygonArea(polygon2D).ToString(lenDec: 2) + "m sq.", LogLevel.NORMAL);
268  else
269  Print("Surface area : not an area", LogLevel.NORMAL);
270 
271  Print("Min/Max slope : [" + (minSlope * Math.RAD2DEG).ToString(lenDec: 2) + "deg / " + (maxSlope * Math.RAD2DEG).ToString(lenDec: 2) + "deg]", LogLevel.NORMAL);
272  Print("Min/Max altitude : [" + minAlt.ToString(lenDec: 2) + "m / " + maxAlt.ToString(lenDec: 2) + "m]", LogLevel.NORMAL);
273  Print("Min/Max alt ATL : [" + minAltATL.ToString(lenDec: 2) + "m / " + maxAltATL.ToString(lenDec: 2) + "m]", LogLevel.NORMAL);
274  }
275 
276 #endif // WORKBENCH
277 
278  //------------------------------------------------------------------------------------------------
279  // constructor
282  void SCR_ShapeAnalyserEntity(IEntitySource src, IEntity parent)
283  {
284  }
285 }
SCR_ShapeAnalyser
Definition: SCR_ShapeAnalyser.c:3
EntityEditorProps
enum EQueryType EntityEditorProps(category:"GameScripted/Sound", description:"THIS IS THE SCRIPT DESCRIPTION.", color:"0 0 255 255")
Definition: SCR_AmbientSoundsComponent.c:12
Attribute
SCR_ShapeAnalyserEntityClass GeneratorBaseEntityClass Attribute(defvalue:"1", category:"Shape", desc:"")
Definition: SCR_ShapeAnalyserEntity.c:8
desc
UI Textures DeployMenu Briefing conflict_HintBanner_1_UI desc
Definition: SCR_RespawnBriefingComponent.c:17
SCR_Ray
Definition: SCR_Ray.c:1
SCR_ShapeAnalyserEntityClass
Definition: SCR_ShapeAnalyserEntity.c:2
DrawDebugShapes
protected void DrawDebugShapes()
Definition: SCR_PowerPole.c:74
params
Configs ServerBrowser KickDialogs params
Definition: SCR_NotificationSenderComponent.c:24
category
params category
Definition: SCR_VehicleDamageManagerComponent.c:180