| 1 | // tPolyModel.cpp  |
| 2 | //  |
| 3 | // This file implements tScene polygonal models. A tPolyModel contains a tMesh and a functional interface over it.  |
| 4 | //  |
| 5 | // Copyright (c) 2006, 2017, 2020 Tristan Grimmer.  |
| 6 | // Permission to use, copy, modify, and/or distribute this software for any purpose with or without fee is hereby  |
| 7 | // granted, provided that the above copyright notice and this permission notice appear in all copies.  |
| 8 | //  |
| 9 | // THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL  |
| 10 | // IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT,  |
| 11 | // INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN  |
| 12 | // AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR  |
| 13 | // PERFORMANCE OF THIS SOFTWARE.  |
| 14 |   |
| 15 | #include <Foundation/tFundamentals.h>  |
| 16 | #include "Scene/tPolyModel.h"  |
| 17 | using namespace tMath;  |
| 18 | namespace tScene  |
| 19 | {  |
| 20 |   |
| 21 |   |
| 22 | void tPolyModel::Save(tChunkWriter& chunk) const  |
| 23 | {  |
| 24 | chunk.Begin(tChunkID::Scene_PolyModel);  |
| 25 | {  |
| 26 | tObject::Save(chunk);  |
| 27 |   |
| 28 | chunk.Begin(tChunkID::Core_Bool);  |
| 29 | {  |
| 30 | chunk.Write(IsLodGroupMember);  |
| 31 | }  |
| 32 | chunk.End();  |
| 33 |   |
| 34 | Mesh.Save(chunk);  |
| 35 | }  |
| 36 | chunk.End();  |
| 37 | }  |
| 38 |   |
| 39 |   |
| 40 | void tPolyModel::Load(const tChunk& modelChunk)  |
| 41 | {  |
| 42 | tAssert(modelChunk.ID() == tChunkID::Scene_PolyModel);  |
| 43 | Clear();  |
| 44 |   |
| 45 | for (tChunk chunk = modelChunk.First(); chunk.Valid(); chunk = chunk.Next())  |
| 46 | {  |
| 47 | switch (chunk.ID())  |
| 48 | {  |
| 49 | case tChunkID::Scene_Object:  |
| 50 | tObject::Load(chunk);  |
| 51 | break;  |
| 52 |   |
| 53 | case tChunkID::Core_Bool:  |
| 54 | chunk.GetItem(IsLodGroupMember);  |
| 55 | break;  |
| 56 |   |
| 57 | case tChunkID::Scene_Mesh:  |
| 58 | Mesh.Load(chunk);  |
| 59 | break;  |
| 60 | }  |
| 61 | }  |
| 62 | }  |
| 63 |   |
| 64 |   |
| 65 | float tPolyModel::ComputeBoundingRadius() const  |
| 66 | {  |
| 67 | float maxRadiusSq = 0.0f;  |
| 68 | for (int v = 0; v < Mesh.NumVertPositions; v++)  |
| 69 | {  |
| 70 | float distSq = Mesh.VertTablePositions[v].LengthSq();  |
| 71 | if (distSq > maxRadiusSq)  |
| 72 | maxRadiusSq = distSq;  |
| 73 | }  |
| 74 |   |
| 75 | return tSqrt(maxRadiusSq);  |
| 76 | }  |
| 77 |   |
| 78 |   |
| 79 | void tPolyModel::ComputeMinMaxRadius(float& minRadius, float& maxRadius) const  |
| 80 | {  |
| 81 | float minRadiusSq = Infinity;  |
| 82 | float maxRadiusSq = 0.0f;  |
| 83 | for (int v = 0; v < Mesh.NumVertPositions; v++)  |
| 84 | {  |
| 85 | float distSq = Mesh.VertTablePositions[v].LengthSq();  |
| 86 | if (distSq > maxRadiusSq)  |
| 87 | maxRadiusSq = distSq;  |
| 88 |   |
| 89 | if (distSq < minRadiusSq)  |
| 90 | minRadiusSq = distSq;  |
| 91 | }  |
| 92 |   |
| 93 | minRadius = tSqrt(minRadiusSq);  |
| 94 | maxRadius = tSqrt(maxRadiusSq);  |
| 95 | }  |
| 96 |   |
| 97 |   |
| 98 | tBox tPolyModel::ComputeBoundingBox() const  |
| 99 | {  |
| 100 | tBox boundingBox;  |
| 101 |   |
| 102 | for (int v = 0; v < Mesh.NumVertPositions; v++)  |
| 103 | boundingBox.AddPoint(Mesh.VertTablePositions[v]);  |
| 104 |   |
| 105 | return boundingBox;  |
| 106 | }  |
| 107 |   |
| 108 |   |
| 109 | float tPolyModel::ComputeApproxArea() const  |
| 110 | {  |
| 111 | // See http://mathworld.wolfram.com/TriangleArea.html and http://mathworld.wolfram.com/Circumradius.html  |
| 112 | float area = 0.0f;  |
| 113 | for (int f = 0; f < Mesh.NumFaces; f++)  |
| 114 | {  |
| 115 | int start = f*3;  |
| 116 | tMath::tTriFace& face = Mesh.FaceTableVertPositionIndices[f];  |
| 117 |   |
| 118 | tVector3& v0 = Mesh.VertTablePositions[face.Index[0]];  |
| 119 | tVector3& v1 = Mesh.VertTablePositions[face.Index[1]];  |
| 120 | tVector3& v2 = Mesh.VertTablePositions[face.Index[2]];  |
| 121 | tVector3 A = v1 - v0; float a = A.NormalizeGetLength();  |
| 122 | tVector3 B = v2 - v0; float b = B.NormalizeGetLength();  |
| 123 | tVector3 C = v1 - v2; float c = C.NormalizeGetLength();  |
| 124 |   |
| 125 | // The link above explains this name.  |
| 126 | float circumradius = a*b*c / tMath::tSqrt((a+b+c)*(b+c+-a)*(c+a-b)*(a+b-c));  |
| 127 | float triArea = a*b*c / (4.0f * circumradius);  |
| 128 | area += triArea;  |
| 129 | }  |
| 130 |   |
| 131 | return area;  |
| 132 | }  |
| 133 |   |
| 134 |   |
| 135 | }  |
| 136 | |