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" 
17using namespace tMath; 
18namespace tScene 
19{ 
20 
21 
22void 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 
40void 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 
65float 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 
79void 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 
98tBox 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 
109float 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