Line data Source code
1 : /*******************************************************************************
2 : * Project: libopencad
3 : * Purpose: OpenSource CAD formats support library
4 : * Author: Alexandr Borzykh, mush3d at gmail.com
5 : * Author: Dmitry Baryshnikov, bishop.dev@gmail.com
6 : * Language: C++
7 : *******************************************************************************
8 : * The MIT License (MIT)
9 : *
10 : * Copyright (c) 2016 Alexandr Borzykh
11 : * Copyright (c) 2016-2018 NextGIS, <info@nextgis.com>
12 : *
13 : * SPDX-License-Identifier: MIT
14 : *******************************************************************************/
15 : #include "cadlayer.h"
16 : #include "cadfile.h"
17 :
18 : #include <cassert>
19 : #include <iostream>
20 : #include <algorithm>
21 :
22 10 : CADLayer::CADLayer( CADFile * file ) :
23 : frozen( false ),
24 : on( true ),
25 : frozenByDefault( false ),
26 : locked( false ),
27 : plotting( false ),
28 : lineWeight( 1 ),
29 : color( 0 ),
30 : layerId( 0 ),
31 : layer_handle( 0 ),
32 10 : pCADFile( file )
33 : {
34 10 : }
35 :
36 28 : std::string CADLayer::getName() const
37 : {
38 28 : return layerName;
39 : }
40 :
41 10 : void CADLayer::setName( const std::string& value )
42 : {
43 10 : layerName = value;
44 10 : }
45 :
46 0 : bool CADLayer::getFrozen() const
47 : {
48 0 : return frozen;
49 : }
50 :
51 10 : void CADLayer::setFrozen( bool value )
52 : {
53 10 : frozen = value;
54 10 : }
55 :
56 0 : bool CADLayer::getOn() const
57 : {
58 0 : return on;
59 : }
60 :
61 10 : void CADLayer::setOn( bool value )
62 : {
63 10 : on = value;
64 10 : }
65 :
66 0 : bool CADLayer::getFrozenByDefault() const
67 : {
68 0 : return frozenByDefault;
69 : }
70 :
71 10 : void CADLayer::setFrozenByDefault( bool value )
72 : {
73 10 : frozenByDefault = value;
74 10 : }
75 :
76 0 : bool CADLayer::getLocked() const
77 : {
78 0 : return locked;
79 : }
80 :
81 10 : void CADLayer::setLocked( bool value )
82 : {
83 10 : locked = value;
84 10 : }
85 :
86 0 : bool CADLayer::getPlotting() const
87 : {
88 0 : return plotting;
89 : }
90 :
91 0 : void CADLayer::setPlotting( bool value )
92 : {
93 0 : plotting = value;
94 0 : }
95 :
96 0 : short CADLayer::getLineWeight() const
97 : {
98 0 : return lineWeight;
99 : }
100 :
101 10 : void CADLayer::setLineWeight( short value )
102 : {
103 10 : lineWeight = value;
104 10 : }
105 :
106 17 : short CADLayer::getColor() const
107 : {
108 17 : return color;
109 : }
110 :
111 10 : void CADLayer::setColor( short value )
112 : {
113 10 : color = value;
114 10 : }
115 :
116 17 : size_t CADLayer::getId() const
117 : {
118 17 : return layerId;
119 : }
120 :
121 10 : void CADLayer::setId( const size_t& value )
122 : {
123 10 : layerId = value;
124 10 : }
125 :
126 21 : long CADLayer::getHandle() const
127 : {
128 21 : return layer_handle;
129 : }
130 :
131 10 : void CADLayer::setHandle( long value )
132 : {
133 10 : layer_handle = value;
134 10 : }
135 :
136 18 : void CADLayer::addHandle( long handle, CADObject::ObjectType type, long cadinserthandle )
137 : {
138 : #ifdef _DEBUG
139 : std::cout << "addHandle: " << handle << " type: " << type << "\n";
140 : #endif //_DEBUG
141 18 : if( type == CADObject::ATTRIB || type == CADObject::ATTDEF )
142 : {
143 4 : auto pCADGeometryPtr = pCADFile->GetGeometry( getId() - 1, handle );
144 8 : std::unique_ptr<CADGeometry> pCADGeometry( pCADGeometryPtr );
145 4 : CADAttdef* attdef = dynamic_cast<CADAttdef*>(pCADGeometry.get());
146 4 : if(attdef)
147 : {
148 4 : attributesNames.insert( attdef->getTag() );
149 : }
150 : }
151 :
152 18 : if( type == CADObject::INSERT )
153 : {
154 : // TODO: transform insert to block of objects (do we need to transform
155 : // coordinates according to insert point)?
156 0 : auto insertPtr = pCADFile->GetObject( handle, false );
157 0 : std::unique_ptr<CADObject> insert( insertPtr );
158 0 : CADInsertObject * pInsert = dynamic_cast<CADInsertObject *>(insert.get());
159 0 : if( nullptr != pInsert )
160 : {
161 0 : std::unique_ptr<CADObject> blockHeader( pCADFile->GetObject(
162 0 : pInsert->hBlockHeader.getAsLong(), false ) );
163 : CADBlockHeaderObject * pBlockHeader =
164 0 : dynamic_cast<CADBlockHeaderObject *>(blockHeader.get());
165 0 : if( nullptr != pBlockHeader )
166 : {
167 : #ifdef _DEBUG
168 : if( pBlockHeader->bBlkisXRef )
169 : {
170 : assert( 0 );
171 : }
172 : #endif //_DEBUG
173 0 : if( pBlockHeader->hEntities.empty() )
174 : {
175 0 : return;
176 : }
177 0 : auto dCurrentEntHandle = pBlockHeader->hEntities[0].getAsLong();
178 0 : auto dLastEntHandle = pBlockHeader->hEntities.back().getAsLong(); // FIXME: in 2000+ entities probably has no links to each other.
179 :
180 0 : if( dCurrentEntHandle == dLastEntHandle ) // Blocks can be empty (contain no objects)
181 : {
182 0 : return;
183 : }
184 :
185 : while( true )
186 : {
187 0 : std::unique_ptr<CADObject> entity(pCADFile->GetObject(
188 0 : dCurrentEntHandle, true ));
189 : CADEntityObject* pEntity =
190 0 : dynamic_cast<CADEntityObject *>( entity.get() );
191 :
192 0 : if( nullptr == pEntity )
193 : {
194 : // shouldn't happen on a valid file, but can happen
195 : // on broken ones
196 0 : break;
197 : }
198 :
199 0 : if( dCurrentEntHandle == handle && type == pEntity->getType() )
200 : {
201 : // If the above condition is true, infinite recursion
202 : // would occur in the following addHandle() call.
203 : // Shouldn't happen on a valid file, but can happen
204 : // on broken ones, such as in https://bugs.chromium.org/p/oss-fuzz/issues/detail?id=46887
205 0 : break;
206 : }
207 :
208 0 : addHandle( dCurrentEntHandle, pEntity->getType(), handle );
209 0 : Matrix mat;
210 0 : mat.translate( pInsert->vertInsertionPoint );
211 0 : mat.scale( pInsert->vertScales );
212 0 : mat.rotate( pInsert->dfRotation );
213 0 : transformations[dCurrentEntHandle] = mat;
214 :
215 0 : if( dCurrentEntHandle == dLastEntHandle )
216 : {
217 0 : break;
218 : }
219 : else
220 : {
221 0 : if( pEntity->stCed.bNoLinks )
222 : {
223 0 : ++dCurrentEntHandle;
224 : }
225 : else
226 : {
227 0 : dCurrentEntHandle =
228 0 : pEntity->stChed.hNextEntity.getAsLong(
229 0 : pEntity->stCed.hObjectHandle );
230 : }
231 : }
232 0 : }
233 : }
234 : }
235 0 : return;
236 : }
237 :
238 18 : if( isCommonEntityType( type ) )
239 : {
240 18 : if( type == CADObject::IMAGE )
241 : {
242 0 : imageHandles.push_back( handle );
243 : }
244 : else
245 : {
246 18 : if( pCADFile->isReadingUnsupportedGeometries() == false )
247 : {
248 18 : if( isSupportedGeometryType( type ) )
249 : {
250 18 : if( geometryTypes.empty() )
251 : {
252 10 : geometryTypes.push_back( type );
253 : }
254 :
255 18 : if( find( geometryTypes.begin(), geometryTypes.end(), type ) ==
256 36 : geometryTypes.end() )
257 : {
258 8 : geometryTypes.push_back( type );
259 : }
260 18 : geometryHandles.push_back(
261 36 : std::make_pair( handle, cadinserthandle ) );
262 : }
263 : }
264 : else
265 : {
266 0 : if( geometryTypes.empty() )
267 : {
268 0 : geometryTypes.push_back( type );
269 : }
270 :
271 0 : if( find( geometryTypes.begin(), geometryTypes.end(), type ) ==
272 0 : geometryTypes.end() )
273 : {
274 0 : geometryTypes.push_back( type );
275 : }
276 0 : geometryHandles.push_back(
277 0 : std::make_pair( handle, cadinserthandle ) );
278 : }
279 : }
280 : }
281 : }
282 :
283 30 : size_t CADLayer::getGeometryCount() const
284 : {
285 30 : return geometryHandles.size();
286 : }
287 :
288 13 : CADGeometry * CADLayer::getGeometry( size_t index )
289 : {
290 13 : auto handleBlockRefPair = geometryHandles[index];
291 13 : CADGeometry * pGeom = pCADFile->GetGeometry( this->getId() - 1,
292 13 : handleBlockRefPair.first, handleBlockRefPair.second );
293 13 : if( nullptr == pGeom )
294 0 : return nullptr;
295 13 : auto iter = transformations.find( handleBlockRefPair.first );
296 13 : if( iter != transformations.end() )
297 : {
298 : // transform geometry if nHandle is in transformations
299 0 : pGeom->transform( iter->second );
300 : }
301 13 : return pGeom;
302 : }
303 :
304 10 : size_t CADLayer::getImageCount() const
305 : {
306 10 : return imageHandles.size();
307 : }
308 :
309 0 : CADImage * CADLayer::getImage( size_t index )
310 : {
311 0 : return static_cast<CADImage *>(pCADFile->GetGeometry( this->getId() - 1,
312 0 : imageHandles[index] ));
313 : }
314 :
315 0 : bool CADLayer::addAttribute( const CADObject * pObject )
316 : {
317 0 : if( nullptr == pObject )
318 0 : return true;
319 :
320 0 : auto attrib = static_cast<const CADAttribObject *>(pObject);
321 0 : for( auto i = geometryAttributes.begin(); i != geometryAttributes.end(); ++i )
322 : {
323 0 : if( i->first == attrib->stChed.hOwner.getAsLong() )
324 : {
325 0 : i->second.insert( make_pair( attrib->sTag, layer_handle ) );
326 0 : return true;
327 : }
328 : }
329 :
330 0 : return false;
331 : }
332 :
333 10 : std::vector<CADObject::ObjectType> CADLayer::getGeometryTypes()
334 : {
335 10 : return geometryTypes;
336 : }
337 :
338 10 : std::unordered_set<std::string> CADLayer::getAttributesTags()
339 : {
340 10 : return attributesNames;
341 : }
|