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 : * Permission is hereby granted, free of charge, to any person obtaining a copy
14 : * of this software and associated documentation files (the "Software"), to deal
15 : * in the Software without restriction, including without limitation the rights
16 : * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
17 : * copies of the Software, and to permit persons to whom the Software is
18 : * furnished to do so, subject to the following conditions:
19 : *
20 : * The above copyright notice and this permission notice shall be included in all
21 : * copies or substantial portions of the Software.
22 : *
23 : * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
24 : * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
25 : * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
26 : * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
27 : * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
28 : * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
29 : * SOFTWARE.
30 : *******************************************************************************/
31 : #include "cadlayer.h"
32 : #include "cadfile.h"
33 :
34 : #include <cassert>
35 : #include <iostream>
36 : #include <algorithm>
37 :
38 10 : CADLayer::CADLayer( CADFile * file ) :
39 : frozen( false ),
40 : on( true ),
41 : frozenByDefault( false ),
42 : locked( false ),
43 : plotting( false ),
44 : lineWeight( 1 ),
45 : color( 0 ),
46 : layerId( 0 ),
47 : layer_handle( 0 ),
48 10 : pCADFile( file )
49 : {
50 10 : }
51 :
52 28 : std::string CADLayer::getName() const
53 : {
54 28 : return layerName;
55 : }
56 :
57 10 : void CADLayer::setName( const std::string& value )
58 : {
59 10 : layerName = value;
60 10 : }
61 :
62 0 : bool CADLayer::getFrozen() const
63 : {
64 0 : return frozen;
65 : }
66 :
67 10 : void CADLayer::setFrozen( bool value )
68 : {
69 10 : frozen = value;
70 10 : }
71 :
72 0 : bool CADLayer::getOn() const
73 : {
74 0 : return on;
75 : }
76 :
77 10 : void CADLayer::setOn( bool value )
78 : {
79 10 : on = value;
80 10 : }
81 :
82 0 : bool CADLayer::getFrozenByDefault() const
83 : {
84 0 : return frozenByDefault;
85 : }
86 :
87 10 : void CADLayer::setFrozenByDefault( bool value )
88 : {
89 10 : frozenByDefault = value;
90 10 : }
91 :
92 0 : bool CADLayer::getLocked() const
93 : {
94 0 : return locked;
95 : }
96 :
97 10 : void CADLayer::setLocked( bool value )
98 : {
99 10 : locked = value;
100 10 : }
101 :
102 0 : bool CADLayer::getPlotting() const
103 : {
104 0 : return plotting;
105 : }
106 :
107 0 : void CADLayer::setPlotting( bool value )
108 : {
109 0 : plotting = value;
110 0 : }
111 :
112 0 : short CADLayer::getLineWeight() const
113 : {
114 0 : return lineWeight;
115 : }
116 :
117 10 : void CADLayer::setLineWeight( short value )
118 : {
119 10 : lineWeight = value;
120 10 : }
121 :
122 17 : short CADLayer::getColor() const
123 : {
124 17 : return color;
125 : }
126 :
127 10 : void CADLayer::setColor( short value )
128 : {
129 10 : color = value;
130 10 : }
131 :
132 17 : size_t CADLayer::getId() const
133 : {
134 17 : return layerId;
135 : }
136 :
137 10 : void CADLayer::setId( const size_t& value )
138 : {
139 10 : layerId = value;
140 10 : }
141 :
142 21 : long CADLayer::getHandle() const
143 : {
144 21 : return layer_handle;
145 : }
146 :
147 10 : void CADLayer::setHandle( long value )
148 : {
149 10 : layer_handle = value;
150 10 : }
151 :
152 18 : void CADLayer::addHandle( long handle, CADObject::ObjectType type, long cadinserthandle )
153 : {
154 : #ifdef _DEBUG
155 : std::cout << "addHandle: " << handle << " type: " << type << "\n";
156 : #endif //_DEBUG
157 18 : if( type == CADObject::ATTRIB || type == CADObject::ATTDEF )
158 : {
159 4 : auto pCADGeometryPtr = pCADFile->GetGeometry( getId() - 1, handle );
160 8 : std::unique_ptr<CADGeometry> pCADGeometry( pCADGeometryPtr );
161 4 : CADAttdef* attdef = dynamic_cast<CADAttdef*>(pCADGeometry.get());
162 4 : if(attdef)
163 : {
164 4 : attributesNames.insert( attdef->getTag() );
165 : }
166 : }
167 :
168 18 : if( type == CADObject::INSERT )
169 : {
170 : // TODO: transform insert to block of objects (do we need to transform
171 : // coordinates according to insert point)?
172 0 : auto insertPtr = pCADFile->GetObject( handle, false );
173 0 : std::unique_ptr<CADObject> insert( insertPtr );
174 0 : CADInsertObject * pInsert = dynamic_cast<CADInsertObject *>(insert.get());
175 0 : if( nullptr != pInsert )
176 : {
177 0 : std::unique_ptr<CADObject> blockHeader( pCADFile->GetObject(
178 0 : pInsert->hBlockHeader.getAsLong(), false ) );
179 : CADBlockHeaderObject * pBlockHeader =
180 0 : dynamic_cast<CADBlockHeaderObject *>(blockHeader.get());
181 0 : if( nullptr != pBlockHeader )
182 : {
183 : #ifdef _DEBUG
184 : if( pBlockHeader->bBlkisXRef )
185 : {
186 : assert( 0 );
187 : }
188 : #endif //_DEBUG
189 0 : if( pBlockHeader->hEntities.empty() )
190 : {
191 0 : return;
192 : }
193 0 : auto dCurrentEntHandle = pBlockHeader->hEntities[0].getAsLong();
194 0 : auto dLastEntHandle = pBlockHeader->hEntities.back().getAsLong(); // FIXME: in 2000+ entities probably has no links to each other.
195 :
196 0 : if( dCurrentEntHandle == dLastEntHandle ) // Blocks can be empty (contain no objects)
197 : {
198 0 : return;
199 : }
200 :
201 : while( true )
202 : {
203 0 : std::unique_ptr<CADObject> entity(pCADFile->GetObject(
204 0 : dCurrentEntHandle, true ));
205 : CADEntityObject* pEntity =
206 0 : dynamic_cast<CADEntityObject *>( entity.get() );
207 :
208 0 : if( nullptr == pEntity )
209 : {
210 : // shouldn't happen on a valid file, but can happen
211 : // on broken ones
212 0 : break;
213 : }
214 :
215 0 : if( dCurrentEntHandle == handle && type == pEntity->getType() )
216 : {
217 : // If the above condition is true, infinite recursion
218 : // would occur in the following addHandle() call.
219 : // Shouldn't happen on a valid file, but can happen
220 : // on broken ones, such as in https://bugs.chromium.org/p/oss-fuzz/issues/detail?id=46887
221 0 : break;
222 : }
223 :
224 0 : addHandle( dCurrentEntHandle, pEntity->getType(), handle );
225 0 : Matrix mat;
226 0 : mat.translate( pInsert->vertInsertionPoint );
227 0 : mat.scale( pInsert->vertScales );
228 0 : mat.rotate( pInsert->dfRotation );
229 0 : transformations[dCurrentEntHandle] = mat;
230 :
231 0 : if( dCurrentEntHandle == dLastEntHandle )
232 : {
233 0 : break;
234 : }
235 : else
236 : {
237 0 : if( pEntity->stCed.bNoLinks )
238 : {
239 0 : ++dCurrentEntHandle;
240 : }
241 : else
242 : {
243 0 : dCurrentEntHandle =
244 0 : pEntity->stChed.hNextEntity.getAsLong(
245 0 : pEntity->stCed.hObjectHandle );
246 : }
247 : }
248 0 : }
249 : }
250 : }
251 0 : return;
252 : }
253 :
254 18 : if( isCommonEntityType( type ) )
255 : {
256 18 : if( type == CADObject::IMAGE )
257 : {
258 0 : imageHandles.push_back( handle );
259 : }
260 : else
261 : {
262 18 : if( pCADFile->isReadingUnsupportedGeometries() == false )
263 : {
264 18 : if( isSupportedGeometryType( type ) )
265 : {
266 18 : if( geometryTypes.empty() )
267 : {
268 10 : geometryTypes.push_back( type );
269 : }
270 :
271 18 : if( find( geometryTypes.begin(), geometryTypes.end(), type ) ==
272 36 : geometryTypes.end() )
273 : {
274 8 : geometryTypes.push_back( type );
275 : }
276 18 : geometryHandles.push_back(
277 36 : std::make_pair( handle, cadinserthandle ) );
278 : }
279 : }
280 : else
281 : {
282 0 : if( geometryTypes.empty() )
283 : {
284 0 : geometryTypes.push_back( type );
285 : }
286 :
287 0 : if( find( geometryTypes.begin(), geometryTypes.end(), type ) ==
288 0 : geometryTypes.end() )
289 : {
290 0 : geometryTypes.push_back( type );
291 : }
292 0 : geometryHandles.push_back(
293 0 : std::make_pair( handle, cadinserthandle ) );
294 : }
295 : }
296 : }
297 : }
298 :
299 30 : size_t CADLayer::getGeometryCount() const
300 : {
301 30 : return geometryHandles.size();
302 : }
303 :
304 13 : CADGeometry * CADLayer::getGeometry( size_t index )
305 : {
306 13 : auto handleBlockRefPair = geometryHandles[index];
307 13 : CADGeometry * pGeom = pCADFile->GetGeometry( this->getId() - 1,
308 13 : handleBlockRefPair.first, handleBlockRefPair.second );
309 13 : if( nullptr == pGeom )
310 0 : return nullptr;
311 13 : auto iter = transformations.find( handleBlockRefPair.first );
312 13 : if( iter != transformations.end() )
313 : {
314 : // transform geometry if nHandle is in transformations
315 0 : pGeom->transform( iter->second );
316 : }
317 13 : return pGeom;
318 : }
319 :
320 10 : size_t CADLayer::getImageCount() const
321 : {
322 10 : return imageHandles.size();
323 : }
324 :
325 0 : CADImage * CADLayer::getImage( size_t index )
326 : {
327 0 : return static_cast<CADImage *>(pCADFile->GetGeometry( this->getId() - 1,
328 0 : imageHandles[index] ));
329 : }
330 :
331 0 : bool CADLayer::addAttribute( const CADObject * pObject )
332 : {
333 0 : if( nullptr == pObject )
334 0 : return true;
335 :
336 0 : auto attrib = static_cast<const CADAttribObject *>(pObject);
337 0 : for( auto i = geometryAttributes.begin(); i != geometryAttributes.end(); ++i )
338 : {
339 0 : if( i->first == attrib->stChed.hOwner.getAsLong() )
340 : {
341 0 : i->second.insert( make_pair( attrib->sTag, layer_handle ) );
342 0 : return true;
343 : }
344 : }
345 :
346 0 : return false;
347 : }
348 :
349 10 : std::vector<CADObject::ObjectType> CADLayer::getGeometryTypes()
350 : {
351 10 : return geometryTypes;
352 : }
353 :
354 10 : std::unordered_set<std::string> CADLayer::getAttributesTags()
355 : {
356 10 : return attributesNames;
357 : }
|