Skyscraper 2.0
utility.cpp
Go to the documentation of this file.
1/*
2 Scalable Building Simulator - Utility Object
3 The Skyscraper Project - Version 2.0
4 Copyright (C)2004-2024 Ryan Thoryk
5 https://www.skyscrapersim.net
6 https://sourceforge.net/projects/skyscraper/
7 Contact - ryan@skyscrapersim.net
8
9 This program is free software; you can redistribute it and/or
10 modify it under the terms of the GNU General Public License
11 as published by the Free Software Foundation; either version 2
12 of the License, or (at your option) any later version.
13
14 This program is distributed in the hope that it will be useful,
15 but WITHOUT ANY WARRANTY; without even the implied warranty of
16 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
17 GNU General Public License for more details.
18
19 You should have received a copy of the GNU General Public License
20 along with this program; if not, write to the Free Software
21 Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
22*/
23
24#include "globals.h"
25#include "sbs.h"
26#include "wall.h"
27#include "polygon.h"
28#include "utility.h"
29
30namespace SBS {
31
33{
35
36 temppoly.reserve(32);
37 temppoly2.reserve(32);
38 temppoly3.reserve(32);
39 temppoly4.reserve(32);
40 temppoly5.reserve(32);
41 worker.reserve(32);
42}
43
45{
46
47}
48
49Vector2 Utility::GetExtents(PolyArray &varray, int coord, bool flip_z)
50{
51 //returns the smallest and largest values from a specified coordinate type
52 //(x, y, or z) from a vertex array (polygon).
53 //first parameter must be a vertex array
54 //second must be either 1 (for x), 2 (for y) or 3 (for z)
55
56 Real esmall = 0;
57 Real ebig = 0;
58 Real tempnum = 0;
59 size_t i = 0;
60
61 //return 0,0 if coord value is out of range
62 if (coord < 1 || coord > 3)
63 return Vector2(0, 0);
64
65 for (i = 0; i < varray.size(); i++)
66 {
67 if (coord == 1)
68 tempnum = varray[i].x;
69 if (coord == 2)
70 tempnum = varray[i].y;
71 if (coord == 3)
72 {
73 if (flip_z == false)
74 tempnum = varray[i].z;
75 else
76 tempnum = -varray[i].z;
77 }
78
79 if (i == 0)
80 {
81 esmall = tempnum;
82 ebig = tempnum;
83 }
84 else
85 {
86 if (tempnum < esmall)
87 esmall = tempnum;
88 if (tempnum > ebig)
89 ebig = tempnum;
90 }
91 }
92
93 return Vector2(esmall, ebig);
94}
95
96void Utility::Cut(Wall *wall, Vector3 start, Vector3 end, bool cutwalls, bool cutfloors, int checkwallnumber, bool reset_check)
97{
98 //cuts a rectangular hole in the polygons within the specified range
99
100 if (cutwalls == false && cutfloors == false)
101 return;
102
103 //swap values if the first is greater than the second
104 if (start.x > end.x)
105 std::swap(start.x, end.x);
106 if (start.y > end.y)
107 std::swap(start.y, end.y);
108 if (start.z > end.z)
109 std::swap(start.z, end.z);
110
111 bool polycheck = false;
112
113 if (reset_check == true)
114 {
115 if (checkwallnumber == 1)
116 {
117 wall1a = false;
118 wall1b = false;
119 }
120 if (checkwallnumber == 2)
121 {
122 wall2a = false;
123 wall2b = false;
124 }
125 }
126
127 //step through each polygon
128 int polycount = wall->GetPolygonCount();
129 for (int i = 0; i < polycount; i++)
130 {
131 //get name
132 Polygon *polygon = wall->GetPolygon(i);
133
134 newpolys.clear();
135
136 //skip empty polygons
137 if (polygon->geometry.size() == 0)
138 continue;
139
140 //cut all polygons within range
141 for (size_t j = 0; j < polygon->geometry.size(); j++)
142 {
143 //skip null geometry
144 if (polygon->geometry[j].size() == 0)
145 continue;
146
147 temppoly.clear();
148 temppoly2.clear();
149 temppoly3.clear();
150 temppoly4.clear();
151 temppoly5.clear();
152 worker.clear();
153 Vector2 extentsx, extentsy, extentsz;
154 Ogre::AxisAlignedBox bounds (start, end);
155 Ogre::AxisAlignedBox polybounds;
156 bool polycheck2 = false;
157
158 //copy source polygon vertices
159 for (size_t k = 0; k < polygon->geometry[j].size(); k++)
160 {
161 Ogre::Vector3 vertex = sbs->ToLocal(polygon->geometry[j][k].vertex);
162 temppoly.emplace_back(vertex);
163 polybounds.merge(vertex);
164 }
165
166 //skip if the polygon is completely inside the bounding box
167 /*if (bounds.contains(polybounds) == true)
168 {
169 polycheck = true;
170 continue;
171 }*/
172
173 //make sure the polygon intersects bounds (is not outside the cut area)
174 if (bounds.intersects(polybounds) == true)
175 {
176 extentsx = GetExtents(temppoly, 1);
177 extentsy = GetExtents(temppoly, 2);
178 extentsz = GetExtents(temppoly, 3);
179
180 //is polygon a wall?
181 if (extentsy.x != extentsy.y)
182 {
183 if (cutwalls == true)
184 {
185 //wall
186 if (std::abs(extentsx.x - extentsx.y) > std::abs(extentsz.x - extentsz.y))
187 {
188 //wall is facing forward/backward
189
190 //get left side
193 worker.clear();
194
195 //get right side
196 if (temppoly2.size() > 0)
198 else
201 worker.clear();
202
203 //get lower
204 if (temppoly3.size() > 0)
206 else if (temppoly2.size() > 0)
208 else if (temppoly.size() > 0)
211 worker.clear();
212
213 //get upper
214 if (temppoly4.size() > 0)
216 else if (temppoly3.size() > 0)
218 else if (temppoly2.size() > 0)
220 else if (temppoly.size() > 0)
223 worker.clear();
224 }
225 else
226 {
227 //wall is facing left/right
228
229 //get left side
232 worker.clear();
233
234 //get right side
235 if (temppoly2.size() > 0)
237 else
240 worker.clear();
241
242 //get lower
243 if (temppoly3.size() > 0)
245 else if (temppoly2.size() > 0)
247 else if (temppoly.size() > 0)
250 worker.clear();
251
252 //get upper
253 if (temppoly4.size() > 0)
255 else if (temppoly3.size() > 0)
257 else if (temppoly2.size() > 0)
259 else if (temppoly.size() > 0)
262 worker.clear();
263 }
264 polycheck = true;
265 polycheck2 = true;
266
267 //store extents of temppoly5 for door sides if needed
268 GetDoorwayExtents(wall->GetMesh(), checkwallnumber, temppoly5);
269 }
270 }
271 else if (cutfloors == true)
272 {
273 //floor
274
275 //get left side
278 worker.clear();
279
280 //get right side
281 if (temppoly2.size() > 0)
283 else
286 worker.clear();
287
288 //get lower
289 if (temppoly3.size() > 0)
291 else if (temppoly2.size() > 0)
293 else if (temppoly.size() > 0)
296 worker.clear();
297
298 //get upper
299 if (temppoly4.size() > 0)
301 else if (temppoly3.size() > 0)
303 else if (temppoly2.size() > 0)
305 else if (temppoly.size() > 0)
308 worker.clear();
309 temppoly5.clear();
310
311 polycheck = true;
312 polycheck2 = true;
313 }
314
315 //create split polygons
316 if (polycheck2 == true)
317 {
318 if (temppoly.size() > 2)
319 {
320 newpolys.resize(newpolys.size() + 1);
321 if (newpolys[newpolys.size() - 1].capacity() < temppoly.size())
322 newpolys[newpolys.size() - 1].reserve(temppoly.size());
323 for (size_t k = 0; k < temppoly.size(); k++)
324 newpolys[newpolys.size() - 1].emplace_back(temppoly[k]);
325 }
326 if (temppoly2.size() > 2)
327 {
328 newpolys.resize(newpolys.size() + 1);
329 if (newpolys[newpolys.size() - 1].capacity() < temppoly2.size())
330 newpolys[newpolys.size() - 1].reserve(temppoly2.size());
331 for (size_t k = 0; k < temppoly2.size(); k++)
332 newpolys[newpolys.size() - 1].emplace_back(temppoly2[k]);
333 }
334 if (temppoly3.size() > 2)
335 {
336 newpolys.resize(newpolys.size() + 1);
337 if (newpolys[newpolys.size() - 1].capacity() < temppoly3.size())
338 newpolys[newpolys.size() - 1].reserve(temppoly3.size());
339 for (size_t k = 0; k < temppoly3.size(); k++)
340 newpolys[newpolys.size() - 1].emplace_back(temppoly3[k]);
341 }
342 if (temppoly4.size() > 2)
343 {
344 newpolys.resize(newpolys.size() + 1);
345 if (newpolys[newpolys.size() - 1].capacity() < temppoly4.size())
346 newpolys[newpolys.size() - 1].reserve(temppoly4.size());
347 for (size_t k = 0; k < temppoly4.size(); k++)
348 newpolys[newpolys.size() - 1].emplace_back(temppoly4[k]);
349 }
350
351 temppoly.clear();
352 temppoly2.clear();
353 temppoly3.clear();
354 temppoly4.clear();
355 }
356 }
357 else
358 {
359 //otherwise put original polygon into array (will only be used if the related submesh is recreated)
360 PolyArray poly;
361 for (size_t k = 0; k < polygon->geometry[j].size(); k++)
362 {
363 poly.emplace_back(sbs->ToLocal(polygon->geometry[j][k].vertex));
364 }
365 newpolys.emplace_back(poly);
366 }
367 }
368
369 //create new polygon
370 if (polycheck == true)
371 {
372 std::string oldmat;
373 Vector3 oldvector;
374 Matrix3 mapping;
375 std::string name = polygon->GetName();
376
377 if (newpolys.size() > 0)
378 {
379 //get texture data from original polygon
380 oldmat = polygon->material;
381 polygon->GetTextureMapping(mapping, oldvector);
382 }
383
384 //delete original polygon
385 wall->DeletePolygon(i, false);
386 polygon = 0;
387
388 //create new polygon
389 if (newpolys.size() > 0)
390 wall->AddPolygonSet(name, oldmat, newpolys, mapping, oldvector);
391
392 //reset search position
393 i--;
394 polycount--;
395 polycheck = false;
396 }
397 }
398}
399
400void Utility::GetDoorwayExtents(MeshObject *mesh, int checknumber, PolyArray &polygon)
401{
402 //calculate doorway extents, for use with AddDoorwayWalls function
403 //checknumber is 1 when checking shaft walls, and 2 when checking floor walls
404
405 if (checknumber > 0 && checknumber < 3)
406 {
407 Vector3 mesh_position = mesh->GetPosition();
408 Real extent;
409
410 if (wall2a == false || wall2b == false)
411 {
412 if (checknumber == 2)
413 {
414 //level walls
415 if (wall2a == true)
416 wall2b = true;
417 wall2a = true;
418 extent = GetExtents(polygon, 1).x + mesh_position.x;
419 if (wall2b == false || (wall2b == true && std::abs(extent - mesh_position.x) > std::abs(wall_extents_x.x - mesh_position.x)))
420 wall_extents_x.x = extent;
421 extent = GetExtents(polygon, 3).x + mesh_position.z;
422 if (wall2b == false || (wall2b == true && std::abs(extent - mesh_position.z) > std::abs(wall_extents_z.x - mesh_position.z)))
423 wall_extents_z.x = extent;
424 wall_extents_y = GetExtents(polygon, 2) + mesh_position.y;
425 }
426 else
427 {
428 //shaft walls
429 if (wall1a == true)
430 wall1b = true;
431 wall1a = true;
432 extent = GetExtents(polygon, 1).y + mesh_position.x;
433 if (wall1b == false || (wall1b == true && std::abs(extent - mesh_position.x) < std::abs(wall_extents_x.y - mesh_position.x)))
434 wall_extents_x.y = extent;
435 extent = GetExtents(polygon, 3).y + mesh_position.z;
436 if (wall1b == false || (wall1b == true && std::abs(extent - mesh_position.z) < std::abs(wall_extents_z.y - mesh_position.z)))
437 wall_extents_z.y = extent;
438 }
439 }
440 }
441}
442
444{
445 //returns the direction the polygon faces, in a 3D vector
446 //for example, <-1, 0, 0> means that the wall faces left.
447
448 //get largest normal
449
450 //convert to remote values for precision compatibility with Alpha 7 and earlier
451 newpoly.clear();
452 for (size_t i = 0; i < polygon.size(); i++)
453 newpoly.emplace_back(sbs->ToRemote(polygon[i], true, false));
454
455 Vector3 normal = ComputePlane(newpoly, false).normal;
456
457 int largest_normal = 0; //x
458
459 if (std::abs(normal.y) >= std::abs(normal.x) && std::abs(normal.y) >= std::abs(normal.z))
460 largest_normal = 1; //y biggest
461 else if (std::abs(normal.z) > std::abs(normal.x))
462 largest_normal = 2; //z biggest
463
464 if (largest_normal == 0)
465 {
466 if (normal.x < 0)
467 return Vector3(1, 0, 0);
468 else
469 return Vector3(-1, 0, 0);
470 }
471
472 if (largest_normal == 1)
473 {
474 if (normal.y < 0)
475 return Vector3(0, 1, 0);
476 else
477 return Vector3(0, -1, 0);
478 }
479
480 if (largest_normal == 2)
481 {
482 if (normal.z < 0)
483 return Vector3(0, 0, 1);
484 else
485 return Vector3(0, 0, -1);
486 }
487 return Vector3(0, 0, 0);
488}
489
490Vector2 Utility::GetEndPoint(const Vector2 &StartPoint, Real angle, Real distance)
491{
492 //calculate 2D endpoint from given starting point, along with angle and distance (magnitude)
493 //angle is in degrees
494
495 angle -= 90;
496 Real newangle = DegreesToRadians(angle);
497 Real x = StartPoint.x + distance * cos(newangle);
498 Real y = -StartPoint.y + distance * sin(newangle);
499 Vector2 result (x, -y);
500 return result;
501
502}
503
504Plane Utility::ComputePlane(PolyArray &vertices, bool flip_normal)
505{
506 //compute plane from a set of given vertices
507
508 Real det;
509 Vector3 normal;
510 if (flip_normal == true)
511 normal = -ComputeNormal(vertices, det);
512 else
513 normal = ComputeNormal(vertices, det);
514 normal.normalise();
515 return Plane(normal, det);
516}
517
519{
520 wall1a = false;
521 wall1b = false;
522 wall2a = false;
523 wall2b = false;
524 wall_extents_x = Vector2::ZERO;
525 wall_extents_y = Vector2::ZERO;
526 wall_extents_z = Vector2::ZERO;
527}
528
529Wall* Utility::AddDoorwayWalls(MeshObject* mesh, const std::string &wallname, const std::string &texture, Real tw, Real th)
530{
531 //add joining doorway polygons if needed
532
533 if (!mesh)
534 return 0;
535
536 if (wall1a == true && wall2a == true)
537 {
538 Wall *wall = mesh->CreateWallObject(wallname);
539
540 //convert extents to relative positioning
541 Vector2 extents_x = wall_extents_x - wall->GetMesh()->GetPosition().x;
542 Vector2 extents_y = wall_extents_y - wall->GetMesh()->GetPosition().y;
543 Vector2 extents_z = wall_extents_z - wall->GetMesh()->GetPosition().z;
544
545 //true if doorway is facing forward/backward
546 //false if doorway is facing left/right
547 bool direction = std::abs(extents_x.x - extents_x.y) > std::abs(extents_z.x - extents_z.y);
548
549 sbs->DrawWalls(false, true, false, false, false, false);
550 if (direction == true)
551 sbs->AddWallMain(wall, "DoorwayLeft", texture, 0, extents_x.x, extents_z.x, extents_x.x, extents_z.y, extents_y.y - extents_y.x, extents_y.y - extents_y.x, extents_y.x, extents_y.x, tw, th, true);
552 else
553 sbs->AddWallMain(wall, "DoorwayLeft", texture, 0, extents_x.x, extents_z.x, extents_x.y, extents_z.x, extents_y.y - extents_y.x, extents_y.y - extents_y.x, extents_y.x, extents_y.x, tw, th, true);
554 sbs->ResetWalls();
555
556 sbs->DrawWalls(true, false, false, false, false, false);
557 if (direction == true)
558 sbs->AddWallMain(wall, "DoorwayRight", texture, 0, extents_x.y, extents_z.x, extents_x.y, extents_z.y, extents_y.y - extents_y.x, extents_y.y - extents_y.x, extents_y.x, extents_y.x, tw, th, true);
559 else
560 sbs->AddWallMain(wall, "DoorwayRight", texture, 0, extents_x.x, extents_z.y, extents_x.y, extents_z.y, extents_y.y - extents_y.x, extents_y.y - extents_y.x, extents_y.x, extents_y.x, tw, th, true);
561
562 sbs->AddFloorMain(wall, "DoorwayTop", texture, 0, extents_x.x, extents_z.x, extents_x.y, extents_z.y, extents_y.y, extents_y.y, false, false, tw, th, true);
563 sbs->ResetWalls();
564
566
567 return wall;
568 }
569
570 return 0;
571}
572
573}
Wall * CreateWallObject(const std::string &name)
Definition mesh.cpp:208
const std::string & GetName()
Definition object.cpp:53
virtual Vector3 GetPosition(bool relative=false)
Definition object.cpp:321
std::string material
Definition polygon.h:56
GeometrySet geometry
Definition polygon.h:47
void GetTextureMapping(Matrix3 &t_matrix, Vector3 &t_vector)
Definition polygon.cpp:74
bool AddWallMain(Wall *wallobject, const std::string &name, const std::string &texture, Real thickness, Real x1, Real z1, Real x2, Real z2, Real height_in1, Real height_in2, Real altitude1, Real altitude2, Real tw, Real th, bool autosize)
Definition sbs.cpp:690
void ResetWalls(bool ToDefaults=false)
Definition sbs.cpp:1854
Real ToLocal(Real remote_value)
Definition sbs.cpp:2367
Real ToRemote(Real local_value)
Definition sbs.cpp:2407
void DrawWalls(bool MainN, bool MainP, bool SideN, bool SideP, bool Top, bool Bottom)
Definition sbs.cpp:1833
bool AddFloorMain(Wall *wallobject, const std::string &name, const std::string &texture, Real thickness, Real x1, Real z1, Real x2, Real z2, Real altitude1, Real altitude2, bool reverse_axis, bool texture_direction, Real tw, Real th, bool autosize, bool legacy_behavior=false)
Definition sbs.cpp:921
Vector2 GetExtents(PolyArray &varray, int coord, bool flip_z=false)
Definition utility.cpp:49
PolyArray worker
Definition utility.h:45
PolyArray newpoly
Definition utility.h:48
PolyArray temppoly5
Definition utility.h:45
void ResetDoorwayWalls()
Definition utility.cpp:518
PolyArray temppoly2
Definition utility.h:45
void SplitWithPlane(int axis, PolyArray &orig, PolyArray &poly1, PolyArray &poly2, Real value)
Definition texmap.cpp:240
Vector3 GetPolygonDirection(PolyArray &polygon)
Definition utility.cpp:443
Utility(Object *parent)
Definition utility.cpp:32
PolyArray temppoly3
Definition utility.h:45
bool wall2b
Definition utility.h:51
PolyArray temppoly
Definition utility.h:45
Vector2 GetEndPoint(const Vector2 &StartPoint, Real angle, Real distance)
Definition utility.cpp:490
bool wall1b
Definition utility.h:51
Wall * AddDoorwayWalls(MeshObject *mesh, const std::string &wallname, const std::string &texture, Real tw, Real th)
Definition utility.cpp:529
bool wall1a
Definition utility.h:51
Vector2 wall_extents_x
Definition utility.h:52
Plane ComputePlane(PolyArray &vertices, bool flip_normal=true)
Definition utility.cpp:504
PolygonSet newpolys
Definition utility.h:46
void Cut(Wall *wall, Vector3 start, Vector3 end, bool cutwalls, bool cutfloors, int checkwallnumber=0, bool reset_check=true)
Definition utility.cpp:96
Vector3 ComputeNormal(PolyArray &vertices, Real &D)
Definition texmap.cpp:343
bool wall2a
Definition utility.h:51
Vector2 wall_extents_y
Definition utility.h:52
Vector2 wall_extents_z
Definition utility.h:52
PolyArray temppoly4
Definition utility.h:45
void GetDoorwayExtents(MeshObject *mesh, int checknumber, PolyArray &polygon)
Definition utility.cpp:400
void DeletePolygon(int index, bool recreate_colliders)
Definition wall.cpp:158
MeshObject * GetMesh()
Definition wall.cpp:258
Polygon * GetPolygon(int index)
Definition wall.cpp:183
int GetPolygonCount()
Definition wall.cpp:178
Polygon * AddPolygonSet(const std::string &name, const std::string &material, PolygonSet &vertices, Matrix3 &tex_matrix, Vector3 &tex_vector)
Definition wall.cpp:112
Ogre::Matrix3 Matrix3
Definition globals.h:64
Ogre::Vector3 Vector3
Definition globals.h:58
Ogre::Real Real
Definition globals.h:57
Ogre::Plane Plane
Definition globals.h:65
Ogre::Vector2 Vector2
Definition globals.h:59
std::vector< Vector3 > PolyArray
Definition sbs.h:118
Real DegreesToRadians(Real degrees)
Definition globals.cpp:115