KiCad PCB EDA Suite
sg_helpers.cpp
Go to the documentation of this file.
1 /*
2  * This program source code file is part of KiCad, a free EDA CAD application.
3  *
4  * Copyright (C) 2015-2017 Cirilo Bernardo <cirilo.bernardo@gmail.com>
5  *
6  * This program is free software; you can redistribute it and/or
7  * modify it under the terms of the GNU General Public License
8  * as published by the Free Software Foundation; either version 2
9  * of the License, or (at your option) any later version.
10  *
11  * This program is distributed in the hope that it will be useful,
12  * but WITHOUT ANY WARRANTY; without even the implied warranty of
13  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14  * GNU General Public License for more details.
15  *
16  * You should have received a copy of the GNU General Public License
17  * along with this program; if not, you may find one here:
18  * http://www.gnu.org/licenses/old-licenses/gpl-2.0.html
19  * or you may search the http://www.gnu.org website for the version 2 license,
20  * or you may write to the Free Software Foundation, Inc.,
21  * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA
22  */
23 
24 
25 #include <iomanip>
26 #include <iostream>
27 #include <map>
28 #include <sstream>
29 #include <utility>
30 #include <wx/log.h>
31 
32 #include "3d_cache/sg/sg_helpers.h"
33 #include "3d_cache/sg/sg_node.h"
34 
35 
36 // formats a floating point number for text output to a VRML file
37 void S3D::FormatFloat( std::string& result, double value )
38 {
39  if( value < 1e-8 && value > -1e-8 )
40  {
41  result = "0";
42  return;
43  }
44 
45  // note: many VRML implementations use float so we use the max.
46  // precision here of 8 digits.
47  std::ostringstream out;
48  out << std::setprecision( 8 ) << value;
49 
50  result = out.str();
51 
52  size_t p = result.find( "." );
53 
54  // trim trailing 0 if appropriate
55 
56  if( std::string::npos == p )
57  return;
58 
59  p = result.find_first_of( "eE" );
60 
61  if( std::string::npos == p )
62  {
63  while( '0' == *(result.rbegin()) )
64  result.erase( result.size() - 1 );
65 
66  return;
67  }
68 
69  if( '0' != result.at( p -1 ) )
70  return;
71 
72  // trim all 0 to the left of 'p'
73  std::string tmp = result.substr( p );
74  result = result.substr( 0, p );
75 
76  while( '0' == *(result.rbegin()) )
77  result.erase( result.size() - 1 );
78 
79  result.append( tmp );
80 
81  return;
82 }
83 
84 // format orientation data for VRML output
85 void S3D::FormatOrientation( std::string& result, const SGVECTOR& axis, double rotation )
86 {
87  double aX;
88  double aY;
89  double aZ;
90 
91  axis.GetVector( aX, aY, aZ );
92  FormatFloat( result, aX );
93  std::string tmp;
94  FormatFloat( tmp, aY );
95  result.append( " " );
96  result.append( tmp );
97  FormatFloat( tmp, aZ );
98  result.append( " " );
99  result.append( tmp );
100  FormatFloat( tmp, rotation );
101  result.append( " " );
102  result.append( tmp );
103 
104  return;
105 }
106 
107 // format point data for VRML output
108 void S3D::FormatPoint( std::string& result, const SGPOINT& point )
109 {
110  FormatFloat( result, point.x );
111 
112  std::string tmp;
113  FormatFloat( tmp, point.y );
114  result.append( " " );
115  result.append( tmp );
116 
117  FormatFloat( tmp, point.z );
118  result.append( " " );
119  result.append( tmp );
120 
121  return;
122 }
123 
124 
125 // format vector data for VRML output
126 void S3D::FormatVector( std::string& result, const SGVECTOR& aVector )
127 {
128  double X, Y, Z;
129  aVector.GetVector( X, Y, Z );
130  FormatFloat( result, X );
131 
132  std::string tmp;
133  FormatFloat( tmp, Y );
134  result.append( " " );
135  result.append( tmp );
136 
137  FormatFloat( tmp, Z );
138  result.append( " " );
139  result.append( tmp );
140 
141  return;
142 }
143 
144 
145 // format Color data for VRML output
146 void S3D::FormatColor( std::string& result, const SGCOLOR& aColor )
147 {
148  float R, G, B;
149  aColor.GetColor( R, G, B );
150  FormatFloat( result, R );
151 
152  std::string tmp;
153  FormatFloat( tmp, G );
154  result.append( " " );
155  result.append( tmp );
156 
157  FormatFloat( tmp, B );
158  result.append( " " );
159  result.append( tmp );
160 
161  return;
162 }
163 
164 
165 bool S3D::WritePoint( std::ostream& aFile, const SGPOINT& aPoint )
166 {
167  aFile.write( (char*)&aPoint.x, sizeof(aPoint.x) );
168  aFile.write( (char*)&aPoint.y, sizeof(aPoint.y) );
169  aFile.write( (char*)&aPoint.z, sizeof(aPoint.z) );
170 
171  if( aFile.fail() )
172  return false;
173 
174  return true;
175 }
176 
177 
178 bool S3D::WriteVector( std::ostream& aFile, const SGVECTOR& aVector )
179 {
180  double x, y, z;
181  aVector.GetVector( x, y, z );
182  aFile.write( (char*)&x, sizeof(double) );
183  aFile.write( (char*)&y, sizeof(double) );
184  aFile.write( (char*)&z, sizeof(double) );
185 
186  if( aFile.fail() )
187  return false;
188 
189  return true;
190 }
191 
192 
193 bool S3D::WriteColor( std::ostream& aFile, const SGCOLOR& aColor )
194 {
195  float r, g, b;
196  aColor.GetColor( r, g, b );
197  aFile.write( (char*)&r, sizeof(float) );
198  aFile.write( (char*)&g, sizeof(float) );
199  aFile.write( (char*)&b, sizeof(float) );
200 
201  if( aFile.fail() )
202  return false;
203 
204  return true;
205 }
206 
207 
208 S3D::SGTYPES S3D::ReadTag( std::istream& aFile, std::string& aName )
209 {
210  char schar;
211  aFile.get( schar );
212 
213  if( '[' != schar )
214  {
215  #ifdef DEBUG
216  std::ostringstream ostr;
217  ostr << __FILE__ << ": " << __FUNCTION__ << ": " << __LINE__ << "\n";
218  ostr << " * [INFO] corrupt data; missing left bracket at position ";
219  ostr << aFile.tellg();
220  wxLogTrace( MASK_3D_SG, "%s\n", ostr.str().c_str() );
221  #endif
222 
223  return S3D::SGTYPE_END;
224  }
225 
226  std::string name;
227  aFile.get( schar );
228 
229  while( ']' != schar && aFile.good() )
230  {
231  name.push_back( schar );
232  aFile.get( schar );
233  }
234 
235  if( schar != ']' )
236  {
237  #ifdef DEBUG
238  std::ostringstream ostr;
239  ostr << __FILE__ << ": " << __FUNCTION__ << ": " << __LINE__ << "\n";
240  ostr << " * [INFO] corrupt data; could not find right bracket";
241  wxLogTrace( MASK_3D_SG, "%s\n", ostr.str().c_str() );
242  #endif
243 
244  return S3D::SGTYPE_END;
245  }
246 
247  aName = name;
248  size_t upos = name.find( '_' );
249 
250  if( std::string::npos == upos )
251  {
252  #ifdef DEBUG
253  std::ostringstream ostr;
254  ostr << __FILE__ << ": " << __FUNCTION__ << ": " << __LINE__ << "\n";
255  ostr << " * [INFO] corrupt data; no underscore in name '";
256  ostr << name << "'";
257  wxLogTrace( MASK_3D_SG, "%s\n", ostr.str().c_str() );
258  #endif
259 
260  return S3D::SGTYPE_END;
261  }
262 
263  name = name.substr( 0, upos );
264  S3D::SGTYPES types[S3D::SGTYPE_END] = {
274  };
275 
276  for( int i = 0; i < S3D::SGTYPE_END; ++i )
277  {
278  if( !name.compare( S3D::GetNodeTypeName( types[i] ) ) )
279  return types[i];
280  }
281 
282  #ifdef DEBUG
283  do {
284  std::ostringstream ostr;
285  ostr << __FILE__ << ": " << __FUNCTION__ << ": " << __LINE__ << "\n";
286  ostr << " * [INFO] corrupt data; no node type matching '";
287  ostr << name << "'";
288  wxLogTrace( MASK_3D_SG, "%s\n", ostr.str().c_str() );
289  } while( 0 );
290  #endif
291 
292  return S3D::SGTYPE_END;
293 }
294 
295 
296 bool S3D::ReadPoint( std::istream& aFile, SGPOINT& aPoint )
297 {
298  aFile.read( (char*)&aPoint.x, sizeof( aPoint.x ) );
299  aFile.read( (char*)&aPoint.y, sizeof( aPoint.y ) );
300  aFile.read( (char*)&aPoint.z, sizeof( aPoint.z ) );
301 
302  if( aFile.fail() )
303  return false;
304 
305  return true;
306 }
307 
308 
309 bool S3D::ReadVector( std::istream& aFile, SGVECTOR& aVector )
310 {
311  double x, y, z;
312  aFile.read( (char*)&x, sizeof(double) );
313  aFile.read( (char*)&y, sizeof(double) );
314  aFile.read( (char*)&z, sizeof(double) );
315  aVector.SetVector( x, y, z );
316 
317  if( aFile.fail() )
318  return false;
319 
320  return true;
321 }
322 
323 
324 bool S3D::ReadColor( std::istream& aFile, SGCOLOR& aColor )
325 {
326  float r, g, b;
327  aFile.read( (char*)&r, sizeof(float) );
328  aFile.read( (char*)&g, sizeof(float) );
329  aFile.read( (char*)&b, sizeof(float) );
330  aColor.SetColor( r, g, b );
331 
332  if( aFile.fail() )
333  return false;
334 
335  return true;
336 }
337 
338 
339 bool S3D::degenerate( glm::dvec3* pts )
340 {
341  double dx, dy, dz;
342 
343  dx = pts[1].x - pts[0].x;
344  dy = pts[1].y - pts[0].y;
345  dz = pts[1].z - pts[0].z;
346 
347  if( ( dx*dx + dy*dy + dz*dz ) < 1e-15 )
348  return true;
349 
350  dx = pts[2].x - pts[0].x;
351  dy = pts[2].y - pts[0].y;
352  dz = pts[2].z - pts[0].z;
353 
354  if( ( dx*dx + dy*dy + dz*dz ) < 1e-15 )
355  return true;
356 
357  dx = pts[2].x - pts[1].x;
358  dy = pts[2].y - pts[1].y;
359  dz = pts[2].z - pts[1].z;
360 
361  if( ( dx*dx + dy*dy + dz*dz ) < 1e-15 )
362  return true;
363 
364  return false;
365 }
366 
367 
368 static void calcTriad( glm::dvec3* pts, glm::dvec3& tri )
369 {
370  if( S3D::degenerate( pts ) )
371  {
372  // degenerate points should contribute nothing to the result
373  tri = glm::dvec3( 0.0, 0.0, 0.0 );
374  return;
375  }
376 
377  // normal * 2 * area
378  tri = glm::cross( pts[1] - pts[0], pts[2] - pts[0] );
379 
380  return;
381 }
382 
383 
384 bool S3D::CalcTriangleNormals( std::vector< SGPOINT > coords,
385  std::vector< int >& index, std::vector< SGVECTOR >& norms )
386 {
387  size_t vsize = coords.size();
388 
389  if( vsize < 3 )
390  {
391  #ifdef DEBUG
392  std::ostringstream ostr;
393  ostr << __FILE__ << ": " << __FUNCTION__ << ": " << __LINE__ << "\n";
394  ostr << " * [INFO] invalid vertex set (fewer than 3 vertices)";
395  wxLogTrace( MASK_3D_SG, "%s\n", ostr.str().c_str() );
396  #endif
397 
398  return false;
399  }
400 
401  size_t isize = index.size();
402 
403  if( 0 != isize % 3 || index.empty() )
404  {
405  #ifdef DEBUG
406  std::ostringstream ostr;
407  ostr << __FILE__ << ": " << __FUNCTION__ << ": " << __LINE__ << "\n";
408  ostr << " * [INFO] invalid index set (not multiple of 3)";
409  wxLogTrace( MASK_3D_SG, "%s\n", ostr.str().c_str() );
410  #endif
411 
412  return false;
413  }
414 
415  if( !norms.empty() )
416  {
417  #ifdef DEBUG
418  std::ostringstream ostr;
419  ostr << __FILE__ << ": " << __FUNCTION__ << ": " << __LINE__ << "\n";
420  ostr << " * [INFO] normals set is not empty";
421  wxLogTrace( MASK_3D_SG, "%s\n", ostr.str().c_str() );
422  #endif
423 
424  return false;
425  }
426 
427  std::map< int, std::list< glm::dvec3 > >vmap;
428 
429  int p1, p2, p3;
430 
431  // create the map of indices to facet sets
432  for( size_t i = 0; i < isize; )
433  {
434  p1 = index[i++];
435  p2 = index[i++];
436  p3 = index[i++];
437 
438  if( p1 < 0 || p1 >= (int)vsize || p2 < 0 || p2 >= (int)vsize ||
439  p3 < 0 || p3 >= (int)vsize )
440  {
441  #ifdef DEBUG
442  std::ostringstream ostr;
443  ostr << __FILE__ << ": " << __FUNCTION__ << ": " << __LINE__ << "\n";
444  ostr << " * [INFO] invalid index set; index out of bounds";
445  wxLogTrace( MASK_3D_SG, "%s\n", ostr.str().c_str() );
446  #endif
447 
448  return false;
449  }
450 
451  glm::dvec3 tri;
452  glm::dvec3 trip[3];
453  trip[0] = glm::dvec3( coords[p1].x, coords[p1].y, coords[p1].z );
454  trip[1] = glm::dvec3( coords[p2].x, coords[p2].y, coords[p2].z );
455  trip[2] = glm::dvec3( coords[p3].x, coords[p3].y, coords[p3].z );
456  calcTriad( trip, tri );
457 
458  std::map< int, std::list< glm::dvec3 > >::iterator ip = vmap.find( p1 );
459 
460  if( ip != vmap.end() )
461  {
462  ip->second.push_back( tri );
463  }
464  else
465  {
466  vmap.insert( std::pair < int, std::list < glm::dvec3 > >
467  ( p1, std::list < glm::dvec3 >( 1, tri ) ) );
468  }
469 
470  ip = vmap.find( p2 );
471 
472  if( ip != vmap.end() )
473  {
474  ip->second.push_back( tri );
475  }
476  else
477  {
478  vmap.insert( std::pair < int, std::list < glm::dvec3 > >
479  ( p2, std::list < glm::dvec3 >( 1, tri ) ) );
480  }
481 
482  ip = vmap.find( p3 );
483 
484  if( ip != vmap.end() )
485  {
486  ip->second.push_back( tri );
487  }
488  else
489  {
490  vmap.insert( std::pair < int, std::list < glm::dvec3 > >
491  ( p3, std::list < glm::dvec3 >( 1, tri ) ) );
492  }
493  }
494 
495  std::map< int, std::list< glm::dvec3 > >::iterator sM = vmap.begin();
496  std::map< int, std::list< glm::dvec3 > >::iterator eM = vmap.end();
497  size_t idx = 0;
498 
499  while( sM != eM )
500  {
501  size_t item = sM->first;
502 
503  // assign any skipped coordinates a normal of (0,0,1)
504  while( item > idx )
505  {
506  norms.push_back( SGVECTOR( 0, 0, 1 ) );
507  ++idx;
508  }
509 
510  std::list< glm::dvec3 >::iterator sT = sM->second.begin();
511  std::list< glm::dvec3 >::iterator eT = sM->second.end();
512  glm::dvec3 norm( 0.0, 0.0, 0.0 );
513 
514  while( sT != eT )
515  {
516  norm += *sT;
517  ++sT;
518  }
519 
520  norms.push_back( SGVECTOR( norm.x, norm.y, norm.z ) );
521 
522  ++idx;
523  ++sM;
524  }
525 
526  if( norms.size() != coords.size() )
527  {
528  #ifdef DEBUG
529  std::ostringstream ostr;
530  ostr << __FILE__ << ": " << __FUNCTION__ << ": " << __LINE__ << "\n";
531  ostr << " * [BUG] number of normals does not equal number of vertices";
532  wxLogTrace( MASK_3D_SG, "%s\n", ostr.str().c_str() );
533  #endif
534 
535  return false;
536  }
537 
538  return true;
539 }
void FormatOrientation(std::string &result, const SGVECTOR &axis, double rotation)
Definition: sg_helpers.cpp:85
double x
Definition: sg_base.h:70
void FormatPoint(std::string &result, const SGPOINT &point)
Definition: sg_helpers.cpp:108
#define G(x, y, z)
Definition: md5_hash.cpp:16
bool ReadColor(std::istream &aFile, SGCOLOR &aColor)
Definition: sg_helpers.cpp:324
void FormatColor(std::string &result, const SGCOLOR &aColor)
Definition: sg_helpers.cpp:146
bool ReadVector(std::istream &aFile, SGVECTOR &aVector)
Definition: sg_helpers.cpp:309
bool CalcTriangleNormals(std::vector< SGPOINT > coords, std::vector< int > &index, std::vector< SGVECTOR > &norms)
Definition: sg_helpers.cpp:384
void SetVector(double aXVal, double aYVal, double aZVal)
Definition: sg_base.cpp:292
bool SetColor(float aRedVal, float aGreenVal, float aBlueVal)
Definition: sg_base.cpp:104
double y
Definition: sg_base.h:71
defines the base class of the intermediate scene graph NODE
bool WriteColor(std::ostream &aFile, const SGCOLOR &aColor)
Definition: sg_helpers.cpp:193
void FormatFloat(std::string &result, double value)
Definition: sg_helpers.cpp:37
void FormatVector(std::string &result, const SGVECTOR &aVector)
Definition: sg_helpers.cpp:126
S3D::SGTYPES ReadTag(std::istream &aFile, std::string &aName)
Function ReadTag reads the text tag of a binary cache file which is the NodeTag and unique ID number ...
Definition: sg_helpers.cpp:208
bool WriteVector(std::ostream &aFile, const SGVECTOR &aVector)
Definition: sg_helpers.cpp:178
bool WritePoint(std::ostream &aFile, const SGPOINT &aPoint)
Definition: sg_helpers.cpp:165
SGTYPES
Definition: sg_types.h:34
bool ReadPoint(std::istream &aFile, SGPOINT &aPoint)
Definition: sg_helpers.cpp:296
static void calcTriad(glm::dvec3 *pts, glm::dvec3 &tri)
Definition: sg_helpers.cpp:368
double z
Definition: sg_base.h:72
const char * name
void GetVector(double &aXVal, double &aYVal, double &aZVal) const
Definition: sg_base.cpp:283
char const * GetNodeTypeName(S3D::SGTYPES aType)
Function GetNodeTypeName returns the name of the given type of node.
Definition: sg_node.cpp:51
defines a number of macro functions to aid in repetitious code which is probably best expressed as a ...
bool degenerate(glm::dvec3 *pts)
Definition: sg_helpers.cpp:339
void GetColor(float &aRedVal, float &aGreenVal, float &aBlueVal) const
Definition: sg_base.cpp:65