1 /* Copyright (c) 2011 Khaled Mamou (kmamou at gmail dot com)
2  All rights reserved.
3 
4 
5  Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met:
6 
7  1. Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer.
8 
9  2. Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following disclaimer in the documentation and/or other materials provided with the distribution.
10 
11  3. The names of the contributors may not be used to endorse or promote products derived from this software without specific prior written permission.
12 
13  THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
14  */
15 #define _CRT_SECURE_NO_WARNINGS
16 
17 #include "LinearMath/btConvexHullComputer.h"
18 #include "vhacdMesh.h"
19 #include <fstream>
20 #include <iosfwd>
21 #include <iostream>
22 #include <stdio.h>
23 #include <stdlib.h>
24 #include <string>
25 
26 namespace VHACD
27 {
Mesh()28 Mesh::Mesh()
29 {
30 	m_diag = 1.0;
31 }
~Mesh()32 Mesh::~Mesh()
33 {
34 }
ComputeVolume() const35 double Mesh::ComputeVolume() const
36 {
37 	const size_t nV = GetNPoints();
38 	const size_t nT = GetNTriangles();
39 	if (nV == 0 || nT == 0)
40 	{
41 		return 0.0;
42 	}
43 
44 	Vec3<double> bary(0.0, 0.0, 0.0);
45 	for (size_t v = 0; v < nV; v++)
46 	{
47 		bary += GetPoint(v);
48 	}
49 	bary /= static_cast<double>(nV);
50 
51 	Vec3<double> ver0, ver1, ver2;
52 	double totalVolume = 0.0;
53 	for (int t = 0; t < nT; t++)
54 	{
55 		const Vec3<int>& tri = GetTriangle(t);
56 		ver0 = GetPoint(tri[0]);
57 		ver1 = GetPoint(tri[1]);
58 		ver2 = GetPoint(tri[2]);
59 		totalVolume += ComputeVolume4(ver0, ver1, ver2, bary);
60 	}
61 	return totalVolume / 6.0;
62 }
63 
ComputeConvexHull(const double * const pts,const size_t nPts)64 void Mesh::ComputeConvexHull(const double* const pts,
65 							 const size_t nPts)
66 {
67 	ResizePoints(0);
68 	ResizeTriangles(0);
69 	btConvexHullComputer ch;
70 	ch.compute(pts, 3 * sizeof(double), (int)nPts, -1.0, -1.0);
71 	for (int v = 0; v < ch.vertices.size(); v++)
72 	{
73 		AddPoint(Vec3<double>(ch.vertices[v].getX(), ch.vertices[v].getY(), ch.vertices[v].getZ()));
74 	}
75 	const int nt = ch.faces.size();
76 	for (int t = 0; t < nt; ++t)
77 	{
78 		const btConvexHullComputer::Edge* sourceEdge = &(ch.edges[ch.faces[t]]);
79 		int a = sourceEdge->getSourceVertex();
80 		int b = sourceEdge->getTargetVertex();
81 		const btConvexHullComputer::Edge* edge = sourceEdge->getNextEdgeOfFace();
82 		int c = edge->getTargetVertex();
83 		while (c != a)
84 		{
85 			AddTriangle(Vec3<int>(a, b, c));
86 			edge = edge->getNextEdgeOfFace();
87 			b = c;
88 			c = edge->getTargetVertex();
89 		}
90 	}
91 }
Clip(const Plane & plane,SArray<Vec3<double>> & positivePart,SArray<Vec3<double>> & negativePart) const92 void Mesh::Clip(const Plane& plane,
93 				SArray<Vec3<double> >& positivePart,
94 				SArray<Vec3<double> >& negativePart) const
95 {
96 	const size_t nV = GetNPoints();
97 	if (nV == 0)
98 	{
99 		return;
100 	}
101 	double d;
102 	for (size_t v = 0; v < nV; v++)
103 	{
104 		const Vec3<double>& pt = GetPoint(v);
105 		d = plane.m_a * pt[0] + plane.m_b * pt[1] + plane.m_c * pt[2] + plane.m_d;
106 		if (d > 0.0)
107 		{
108 			positivePart.PushBack(pt);
109 		}
110 		else if (d < 0.0)
111 		{
112 			negativePart.PushBack(pt);
113 		}
114 		else
115 		{
116 			positivePart.PushBack(pt);
117 			negativePart.PushBack(pt);
118 		}
119 	}
120 }
IsInside(const Vec3<double> & pt) const121 bool Mesh::IsInside(const Vec3<double>& pt) const
122 {
123 	const size_t nV = GetNPoints();
124 	const size_t nT = GetNTriangles();
125 	if (nV == 0 || nT == 0)
126 	{
127 		return false;
128 	}
129 	Vec3<double> ver0, ver1, ver2;
130 	double volume;
131 	for (int t = 0; t < nT; t++)
132 	{
133 		const Vec3<int>& tri = GetTriangle(t);
134 		ver0 = GetPoint(tri[0]);
135 		ver1 = GetPoint(tri[1]);
136 		ver2 = GetPoint(tri[2]);
137 		volume = ComputeVolume4(ver0, ver1, ver2, pt);
138 		if (volume < 0.0)
139 		{
140 			return false;
141 		}
142 	}
143 	return true;
144 }
ComputeDiagBB()145 double Mesh::ComputeDiagBB()
146 {
147 	const size_t nPoints = GetNPoints();
148 	if (nPoints == 0)
149 		return 0.0;
150 	Vec3<double> minBB = m_points[0];
151 	Vec3<double> maxBB = m_points[0];
152 	double x, y, z;
153 	for (size_t v = 1; v < nPoints; v++)
154 	{
155 		x = m_points[v][0];
156 		y = m_points[v][1];
157 		z = m_points[v][2];
158 		if (x < minBB[0])
159 			minBB[0] = x;
160 		else if (x > maxBB[0])
161 			maxBB[0] = x;
162 		if (y < minBB[1])
163 			minBB[1] = y;
164 		else if (y > maxBB[1])
165 			maxBB[1] = y;
166 		if (z < minBB[2])
167 			minBB[2] = z;
168 		else if (z > maxBB[2])
169 			maxBB[2] = z;
170 	}
171 	return (m_diag = (maxBB - minBB).GetNorm());
172 }
173 
174 #ifdef VHACD_DEBUG_MESH
SaveVRML2(const std::string & fileName) const175 bool Mesh::SaveVRML2(const std::string& fileName) const
176 {
177 	std::ofstream fout(fileName.c_str());
178 	if (fout.is_open())
179 	{
180 		const Material material;
181 
182 		if (SaveVRML2(fout, material))
183 		{
184 			fout.close();
185 			return true;
186 		}
187 		return false;
188 	}
189 	return false;
190 }
SaveVRML2(std::ofstream & fout,const Material & material) const191 bool Mesh::SaveVRML2(std::ofstream& fout, const Material& material) const
192 {
193 	if (fout.is_open())
194 	{
195 		fout.setf(std::ios::fixed, std::ios::floatfield);
196 		fout.setf(std::ios::showpoint);
197 		fout.precision(6);
198 		size_t nV = m_points.Size();
199 		size_t nT = m_triangles.Size();
200 		fout << "#VRML V2.0 utf8" << std::endl;
201 		fout << "" << std::endl;
202 		fout << "# Vertices: " << nV << std::endl;
203 		fout << "# Triangles: " << nT << std::endl;
204 		fout << "" << std::endl;
205 		fout << "Group {" << std::endl;
206 		fout << "    children [" << std::endl;
207 		fout << "        Shape {" << std::endl;
208 		fout << "            appearance Appearance {" << std::endl;
209 		fout << "                material Material {" << std::endl;
210 		fout << "                    diffuseColor " << material.m_diffuseColor[0] << " "
211 			 << material.m_diffuseColor[1] << " "
212 			 << material.m_diffuseColor[2] << std::endl;
213 		fout << "                    ambientIntensity " << material.m_ambientIntensity << std::endl;
214 		fout << "                    specularColor " << material.m_specularColor[0] << " "
215 			 << material.m_specularColor[1] << " "
216 			 << material.m_specularColor[2] << std::endl;
217 		fout << "                    emissiveColor " << material.m_emissiveColor[0] << " "
218 			 << material.m_emissiveColor[1] << " "
219 			 << material.m_emissiveColor[2] << std::endl;
220 		fout << "                    shininess " << material.m_shininess << std::endl;
221 		fout << "                    transparency " << material.m_transparency << std::endl;
222 		fout << "                }" << std::endl;
223 		fout << "            }" << std::endl;
224 		fout << "            geometry IndexedFaceSet {" << std::endl;
225 		fout << "                ccw TRUE" << std::endl;
226 		fout << "                solid TRUE" << std::endl;
227 		fout << "                convex TRUE" << std::endl;
228 		if (nV > 0)
229 		{
230 			fout << "                coord DEF co Coordinate {" << std::endl;
231 			fout << "                    point [" << std::endl;
232 			for (size_t v = 0; v < nV; v++)
233 			{
234 				fout << "                        " << m_points[v][0] << " "
235 					 << m_points[v][1] << " "
236 					 << m_points[v][2] << "," << std::endl;
237 			}
238 			fout << "                    ]" << std::endl;
239 			fout << "                }" << std::endl;
240 		}
241 		if (nT > 0)
242 		{
243 			fout << "                coordIndex [ " << std::endl;
244 			for (size_t f = 0; f < nT; f++)
245 			{
246 				fout << "                        " << m_triangles[f][0] << ", "
247 					 << m_triangles[f][1] << ", "
248 					 << m_triangles[f][2] << ", -1," << std::endl;
249 			}
250 			fout << "                ]" << std::endl;
251 		}
252 		fout << "            }" << std::endl;
253 		fout << "        }" << std::endl;
254 		fout << "    ]" << std::endl;
255 		fout << "}" << std::endl;
256 		return true;
257 	}
258 	return false;
259 }
SaveOFF(const std::string & fileName) const260 bool Mesh::SaveOFF(const std::string& fileName) const
261 {
262 	std::ofstream fout(fileName.c_str());
263 	if (fout.is_open())
264 	{
265 		size_t nV = m_points.Size();
266 		size_t nT = m_triangles.Size();
267 		fout << "OFF" << std::endl;
268 		fout << nV << " " << nT << " " << 0 << std::endl;
269 		for (size_t v = 0; v < nV; v++)
270 		{
271 			fout << m_points[v][0] << " "
272 				 << m_points[v][1] << " "
273 				 << m_points[v][2] << std::endl;
274 		}
275 		for (size_t f = 0; f < nT; f++)
276 		{
277 			fout << "3 " << m_triangles[f][0] << " "
278 				 << m_triangles[f][1] << " "
279 				 << m_triangles[f][2] << std::endl;
280 		}
281 		fout.close();
282 		return true;
283 	}
284 	return false;
285 }
286 
LoadOFF(const std::string & fileName,bool invert)287 bool Mesh::LoadOFF(const std::string& fileName, bool invert)
288 {
289 	FILE* fid = fopen(fileName.c_str(), "r");
290 	if (fid)
291 	{
292 		const std::string strOFF("OFF");
293 		char temp[1024];
294 		fscanf(fid, "%s", temp);
295 		if (std::string(temp) != strOFF)
296 		{
297 			fclose(fid);
298 			return false;
299 		}
300 		else
301 		{
302 			int nv = 0;
303 			int nf = 0;
304 			int ne = 0;
305 			fscanf(fid, "%i", &nv);
306 			fscanf(fid, "%i", &nf);
307 			fscanf(fid, "%i", &ne);
308 			m_points.Resize(nv);
309 			m_triangles.Resize(nf);
310 			Vec3<double> coord;
311 			float x, y, z;
312 			for (int p = 0; p < nv; p++)
313 			{
314 				fscanf(fid, "%f", &x);
315 				fscanf(fid, "%f", &y);
316 				fscanf(fid, "%f", &z);
317 				m_points[p][0] = x;
318 				m_points[p][1] = y;
319 				m_points[p][2] = z;
320 			}
321 			int i, j, k, s;
322 			for (int t = 0; t < nf; ++t)
323 			{
324 				fscanf(fid, "%i", &s);
325 				if (s == 3)
326 				{
327 					fscanf(fid, "%i", &i);
328 					fscanf(fid, "%i", &j);
329 					fscanf(fid, "%i", &k);
330 					m_triangles[t][0] = i;
331 					if (invert)
332 					{
333 						m_triangles[t][1] = k;
334 						m_triangles[t][2] = j;
335 					}
336 					else
337 					{
338 						m_triangles[t][1] = j;
339 						m_triangles[t][2] = k;
340 					}
341 				}
342 				else  // Fix me: support only triangular meshes
343 				{
344 					for (int h = 0; h < s; ++h)
345 						fscanf(fid, "%i", &s);
346 				}
347 			}
348 			fclose(fid);
349 		}
350 	}
351 	else
352 	{
353 		return false;
354 	}
355 	return true;
356 }
357 #endif  // VHACD_DEBUG_MESH
358 }  // namespace VHACD
359