KiCad PCB EDA Suite
sg_coords.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 <[email protected]>
5 * Copyright (C) 2020 KiCad Developers, see AUTHORS.txt for contributors.
6 *
7 * This program is free software; you can redistribute it and/or
8 * modify it under the terms of the GNU General Public License
9 * as published by the Free Software Foundation; either version 2
10 * of the License, or (at your option) any later version.
11 *
12 * This program is distributed in the hope that it will be useful,
13 * but WITHOUT ANY WARRANTY; without even the implied warranty of
14 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15 * GNU General Public License for more details.
16 *
17 * You should have received a copy of the GNU General Public License
18 * along with this program; if not, you may find one here:
19 * http://www.gnu.org/licenses/old-licenses/gpl-2.0.html
20 * or you may search the http://www.gnu.org website for the version 2 license,
21 * or you may write to the Free Software Foundation, Inc.,
22 * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA
23 */
24
25#include <iostream>
26#include <sstream>
27#include <wx/log.h>
28
33
34
35SGCOORDS::SGCOORDS( SGNODE* aParent ) : SGNODE( aParent )
36{
38
39 if( nullptr != aParent && S3D::SGTYPE_FACESET != aParent->GetNodeType() )
40 {
41 m_Parent = nullptr;
42
43 wxLogTrace( MASK_3D_SG,
44 wxT( "%s:%s:%d * [BUG] inappropriate parent to SGCOORDS (type %s)" ),
45 __FILE__, __FUNCTION__, __LINE__, aParent->GetNodeType() );
46 }
47 else if( nullptr != aParent && S3D::SGTYPE_FACESET == aParent->GetNodeType() )
48 {
49 m_Parent->AddChildNode( this );
50 }
51}
52
53
55{
56 coords.clear();
57}
58
59
60bool SGCOORDS::SetParent( SGNODE* aParent, bool notify )
61{
62 if( nullptr != m_Parent )
63 {
64 if( aParent == m_Parent )
65 return true;
66
67 // handle the change in parents
68 if( notify )
70
71 m_Parent = nullptr;
72
73 if( nullptr == aParent )
74 return true;
75 }
76
77 // only a SGFACESET may be parent to a SGCOORDS
78 if( nullptr != aParent && S3D::SGTYPE_FACESET != aParent->GetNodeType() )
79 return false;
80
81 m_Parent = aParent;
82
83 if( m_Parent )
84 m_Parent->AddChildNode( this );
85
86 return true;
87}
88
89
90SGNODE* SGCOORDS::FindNode(const char *aNodeName, const SGNODE *aCaller) noexcept
91{
92 if( nullptr == aNodeName || 0 == aNodeName[0] )
93 return nullptr;
94
95 if( !m_Name.compare( aNodeName ) )
96 return this;
97
98 return nullptr;
99}
100
101
102void SGCOORDS::unlinkChildNode( const SGNODE* aCaller ) noexcept
103{
104 wxCHECK( aCaller, /* void */ );
105}
106
107
108void SGCOORDS::unlinkRefNode( const SGNODE* aCaller ) noexcept
109{
110 wxCHECK( aCaller, /* void */ );
111}
112
113
114bool SGCOORDS::AddRefNode( SGNODE* aNode ) noexcept
115{
116 wxCHECK( aNode, false );
117
118 return false;
119}
120
121
122bool SGCOORDS::AddChildNode( SGNODE* aNode ) noexcept
123{
124 wxCHECK( aNode, false );
125
126 return false;
127}
128
129
130bool SGCOORDS::GetCoordsList( size_t& aListSize, SGPOINT*& aCoordsList )
131{
132 if( coords.empty() )
133 {
134 aListSize = 0;
135 aCoordsList = nullptr;
136 return false;
137 }
138
139 aListSize = coords.size();
140 aCoordsList = &coords[0];
141 return true;
142}
143
144
145void SGCOORDS::SetCoordsList( size_t aListSize, const SGPOINT* aCoordsList )
146{
147 coords.clear();
148
149 if( 0 == aListSize || nullptr == aCoordsList )
150 return;
151
152 for( size_t i = 0; i < aListSize; ++i )
153 coords.push_back( aCoordsList[i] );
154}
155
156
157void SGCOORDS::AddCoord( double aXValue, double aYValue, double aZValue )
158{
159 coords.emplace_back( aXValue, aYValue, aZValue );
160}
161
162
163void SGCOORDS::AddCoord( const SGPOINT& aPoint )
164{
165 coords.push_back( aPoint );
166}
167
168
170{
171 m_written = false;
172
173 // rename this node
174 m_Name.clear();
175 GetName();
176}
177
178
179bool SGCOORDS::WriteVRML( std::ostream& aFile, bool aReuseFlag )
180{
181 if( coords.empty() )
182 return false;
183
184 if( aReuseFlag )
185 {
186 if( !m_written )
187 {
188 aFile << " coord DEF " << GetName() << " Coordinate { point [\n ";
189 m_written = true;
190 }
191 else
192 {
193 aFile << " coord USE " << GetName() << "\n";
194 return true;
195 }
196 }
197 else
198 {
199 aFile << " coord Coordinate { point [\n ";
200 }
201
202 std::string tmp;
203 size_t n = coords.size();
204 bool nline = false;
205 SGPOINT pt;
206
207 for( size_t i = 0; i < n; )
208 {
209 // ensure VRML output has 1U = 0.1 inch as per legacy kicad expectations
210 pt = coords[i];
211 pt.x /= 2.54;
212 pt.y /= 2.54;
213 pt.z /= 2.54;
214 S3D::FormatPoint( tmp, pt );
215 aFile << tmp ;
216 ++i;
217
218 if( i < n )
219 {
220 aFile << ",";
221
222 if( nline )
223 {
224 aFile << "\n ";
225 nline = false;
226 }
227 else
228 {
229 nline = true;
230 }
231
232 }
233 }
234
235 aFile << "] }\n";
236
237 return true;
238}
239
240
241bool SGCOORDS::WriteCache( std::ostream& aFile, SGNODE* parentNode )
242{
243 if( nullptr == parentNode )
244 {
245 wxCHECK( m_Parent, false );
246
247 SGNODE* np = m_Parent;
248
249 while( nullptr != np->GetParent() )
250 np = np->GetParent();
251
252 if( np->WriteCache( aFile, nullptr ) )
253 {
254 m_written = true;
255 return true;
256 }
257
258 return false;
259 }
260
261 wxCHECK( parentNode == m_Parent, false );
262
263 if( !aFile.good() )
264 {
265 wxLogTrace( MASK_3D_SG, wxT( "%s:%s:%d * [INFO] bad stream" ),
266 __FILE__, __FUNCTION__, __LINE__ );
267
268 return false;
269 }
270
271 aFile << "[" << GetName() << "]";
272 size_t npts = coords.size();
273 aFile.write( (char*)&npts, sizeof(size_t) );
274
275 for( size_t i = 0; i < npts; ++i )
276 S3D::WritePoint( aFile, coords[i] );
277
278 if( aFile.fail() )
279 return false;
280
281 m_written = true;
282 return true;
283}
284
285
286bool SGCOORDS::ReadCache( std::istream& aFile, SGNODE* parentNode )
287{
288 wxCHECK( coords.empty(), false );
289
290 size_t npts;
291 aFile.read( (char*) &npts, sizeof( size_t ) );
292 SGPOINT tmp;
293
294 if( aFile.fail() )
295 return false;
296
297 for( size_t i = 0; i < npts; ++i )
298 {
299 if( !S3D::ReadPoint( aFile, tmp ) || aFile.fail() )
300 return false;
301
302 coords.push_back( tmp );
303 }
304
305 return true;
306}
307
308
309bool SGCOORDS::CalcNormals( SGFACESET* callingNode, SGNODE** aPtr )
310{
311 if( aPtr )
312 *aPtr = nullptr;
313
314 if( nullptr == m_Parent || nullptr == callingNode )
315 return false;
316
317 // the parent and all references must have indices; collect all
318 // indices into one std::vector<>
319 std::vector< int > ilist;
320 SGNORMALS* np = nullptr;
321
322 if( callingNode == m_Parent )
323 {
324 ((SGFACESET*)m_Parent)->GatherCoordIndices( ilist );
325
326 std::list< SGNODE* >::iterator sB = m_BackPointers.begin();
327 std::list< SGNODE* >::iterator eB = m_BackPointers.end();
328
329 while( sB != eB )
330 {
331 SGFACESET* fp = (SGFACESET*)(*sB);
332 fp->GatherCoordIndices( ilist );
333 ++sB;
334 }
335
336 np = ( (SGFACESET*) m_Parent )->m_Normals;
337
338 if( !np )
339 np = new SGNORMALS( m_Parent );
340
341 }
342 else
343 {
344 callingNode->GatherCoordIndices( ilist );
345 np = callingNode->m_Normals;
346
347 if( !np )
348 np = new SGNORMALS( callingNode );
349
350 }
351
352 if( S3D::CalcTriangleNormals( coords, ilist, np->norms ) )
353 {
354 if( aPtr )
355 *aPtr = np;
356
357 return true;
358 }
359
360 delete np;
361
362 return false;
363}
bool WriteCache(std::ostream &aFile, SGNODE *parentNode) override
Write this node's data to a binary cache file.
Definition: sg_coords.cpp:241
void unlinkChildNode(const SGNODE *aNode) noexcept override
Remove references to an owned child.
Definition: sg_coords.cpp:102
void unlinkRefNode(const SGNODE *aNode) noexcept override
Remove pointers to a referenced node.
Definition: sg_coords.cpp:108
bool WriteVRML(std::ostream &aFile, bool aReuseFlag) override
Writes this node's data to a VRML file.
Definition: sg_coords.cpp:179
std::vector< SGPOINT > coords
Definition: sg_coords.h:72
bool AddRefNode(SGNODE *aNode) noexcept override
Definition: sg_coords.cpp:114
void AddCoord(double aXValue, double aYValue, double aZValue)
Definition: sg_coords.cpp:157
bool ReadCache(std::istream &aFile, SGNODE *parentNode) override
Reads binary format data from a cache file.
Definition: sg_coords.cpp:286
SGCOORDS(SGNODE *aParent)
Definition: sg_coords.cpp:35
SGNODE * FindNode(const char *aNodeName, const SGNODE *aCaller) noexcept override
Search the tree of linked nodes and return a reference to the first node found with the given name.
Definition: sg_coords.cpp:90
virtual bool SetParent(SGNODE *aParent, bool notify=true) override
Set the parent SGNODE of this object.
Definition: sg_coords.cpp:60
bool AddChildNode(SGNODE *aNode) noexcept override
Definition: sg_coords.cpp:122
bool GetCoordsList(size_t &aListSize, SGPOINT *&aCoordsList)
Definition: sg_coords.cpp:130
void ReNameNodes(void) override
Rename a node and all its child nodes in preparation for write operations.
Definition: sg_coords.cpp:169
virtual ~SGCOORDS()
Definition: sg_coords.cpp:54
void SetCoordsList(size_t aListSize, const SGPOINT *aCoordsList)
Definition: sg_coords.cpp:145
bool CalcNormals(SGFACESET *callingNode, SGNODE **aPtr=nullptr)
Calculate normals for this coordinate list and sets the normals list in the parent SGFACESET.
Definition: sg_coords.cpp:309
Define an indexed face set for a scenegraph.
Definition: sg_faceset.h:47
void GatherCoordIndices(std::vector< int > &aIndexList)
Add all internal coordinate indices to the given list in preparation for a normals calculation.
Definition: sg_faceset.cpp:968
SGNORMALS * m_Normals
Definition: sg_faceset.h:82
The base class of all Scene Graph nodes.
Definition: sg_node.h:75
virtual bool WriteCache(std::ostream &aFile, SGNODE *parentNode)=0
Write this node's data to a binary cache file.
const char * GetName(void)
Definition: sg_node.cpp:146
SGNODE * GetParent(void) const noexcept
Returns a pointer to the parent SGNODE of this object or NULL if the object has no parent (ie.
Definition: sg_node.cpp:110
S3D::SGTYPES GetNodeType(void) const noexcept
Return the type of this node instance.
Definition: sg_node.cpp:104
virtual bool AddChildNode(SGNODE *aNode)=0
std::list< SGNODE * > m_BackPointers
nodes which hold a reference to this.
Definition: sg_node.h:226
SGNODE * m_Parent
Pointer to parent node; may be NULL for top level transform.
Definition: sg_node.h:227
std::string m_Name
name to use for referencing the entity by name.
Definition: sg_node.h:229
virtual void unlinkChildNode(const SGNODE *aNode)=0
Remove references to an owned child.
bool m_written
Set to true when the object has been written after a ReNameNodes().
Definition: sg_node.h:230
S3D::SGTYPES m_SGtype
Type of Scene Graph node.
Definition: sg_node.h:228
Define a set of vertex normals for a scene graph object.
Definition: sg_normals.h:39
std::vector< SGVECTOR > norms
Definition: sg_normals.h:64
double z
Definition: sg_base.h:72
double x
Definition: sg_base.h:70
double y
Definition: sg_base.h:71
bool ReadPoint(std::istream &aFile, SGPOINT &aPoint)
Definition: sg_helpers.cpp:267
bool WritePoint(std::ostream &aFile, const SGPOINT &aPoint)
Definition: sg_helpers.cpp:152
bool CalcTriangleNormals(std::vector< SGPOINT > coords, std::vector< int > &index, std::vector< SGVECTOR > &norms)
Definition: sg_helpers.cpp:353
void FormatPoint(std::string &result, const SGPOINT &point)
Definition: sg_helpers.cpp:103
@ SGTYPE_FACESET
Definition: sg_types.h:40
@ SGTYPE_COORDS
Definition: sg_types.h:41
Define a number of macros to aid in repetitious code which is probably best expressed as a preprocess...