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 
CADLayer(CADFile * file)38 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     pCADFile( file )
49 {
50 }
51 
getName() const52 std::string CADLayer::getName() const
53 {
54     return layerName;
55 }
56 
setName(const std::string & value)57 void CADLayer::setName( const std::string& value )
58 {
59     layerName = value;
60 }
61 
getFrozen() const62 bool CADLayer::getFrozen() const
63 {
64     return frozen;
65 }
66 
setFrozen(bool value)67 void CADLayer::setFrozen( bool value )
68 {
69     frozen = value;
70 }
71 
getOn() const72 bool CADLayer::getOn() const
73 {
74     return on;
75 }
76 
setOn(bool value)77 void CADLayer::setOn( bool value )
78 {
79     on = value;
80 }
81 
getFrozenByDefault() const82 bool CADLayer::getFrozenByDefault() const
83 {
84     return frozenByDefault;
85 }
86 
setFrozenByDefault(bool value)87 void CADLayer::setFrozenByDefault( bool value )
88 {
89     frozenByDefault = value;
90 }
91 
getLocked() const92 bool CADLayer::getLocked() const
93 {
94     return locked;
95 }
96 
setLocked(bool value)97 void CADLayer::setLocked( bool value )
98 {
99     locked = value;
100 }
101 
getPlotting() const102 bool CADLayer::getPlotting() const
103 {
104     return plotting;
105 }
106 
setPlotting(bool value)107 void CADLayer::setPlotting( bool value )
108 {
109     plotting = value;
110 }
111 
getLineWeight() const112 short CADLayer::getLineWeight() const
113 {
114     return lineWeight;
115 }
116 
setLineWeight(short value)117 void CADLayer::setLineWeight( short value )
118 {
119     lineWeight = value;
120 }
121 
getColor() const122 short CADLayer::getColor() const
123 {
124     return color;
125 }
126 
setColor(short value)127 void CADLayer::setColor( short value )
128 {
129     color = value;
130 }
131 
getId() const132 size_t CADLayer::getId() const
133 {
134     return layerId;
135 }
136 
setId(const size_t & value)137 void CADLayer::setId( const size_t& value )
138 {
139     layerId = value;
140 }
141 
getHandle() const142 long CADLayer::getHandle() const
143 {
144     return layer_handle;
145 }
146 
setHandle(long value)147 void CADLayer::setHandle( long value )
148 {
149     layer_handle = value;
150 }
151 
addHandle(long handle,CADObject::ObjectType type,long cadinserthandle)152 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     if( type == CADObject::ATTRIB || type == CADObject::ATTDEF )
158     {
159         auto pCADGeometryPtr = pCADFile->GetGeometry( getId() - 1, handle );
160         std::unique_ptr<CADGeometry> pCADGeometry( pCADGeometryPtr );
161         CADAttdef* attdef = dynamic_cast<CADAttdef*>(pCADGeometry.get());
162         if(attdef)
163         {
164             attributesNames.insert( attdef->getTag() );
165         }
166     }
167 
168     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         auto insertPtr = pCADFile->GetObject( handle, false );
173         std::unique_ptr<CADObject> insert( insertPtr );
174         CADInsertObject * pInsert = dynamic_cast<CADInsertObject *>(insert.get());
175         if( nullptr != pInsert )
176         {
177             std::unique_ptr<CADObject> blockHeader( pCADFile->GetObject(
178                                     pInsert->hBlockHeader.getAsLong(), false ) );
179             CADBlockHeaderObject * pBlockHeader =
180                           dynamic_cast<CADBlockHeaderObject *>(blockHeader.get());
181             if( nullptr != pBlockHeader )
182             {
183 #ifdef _DEBUG
184                 if( pBlockHeader->bBlkisXRef )
185                 {
186                     assert( 0 );
187                 }
188 #endif //_DEBUG
189                 auto dCurrentEntHandle = pBlockHeader->hEntities[0].getAsLong();
190                 auto dLastEntHandle    = pBlockHeader->hEntities.back().getAsLong(); // FIXME: in 2000+ entities probably has no links to each other.
191 
192                 if( dCurrentEntHandle == dLastEntHandle ) // Blocks can be empty (contain no objects)
193                 {
194                     return;
195                 }
196 
197                 while( true )
198                 {
199                     std::unique_ptr<CADObject> entity(pCADFile->GetObject(
200                                                        dCurrentEntHandle, true ));
201                     CADEntityObject* pEntity =
202                             dynamic_cast<CADEntityObject *>( entity.get() );
203 
204                     if( dCurrentEntHandle == dLastEntHandle )
205                     {
206                         if( nullptr != pEntity )
207                         {
208                             addHandle( dCurrentEntHandle, pEntity->getType(), handle );
209                             Matrix mat;
210                             mat.translate( pInsert->vertInsertionPoint );
211                             mat.scale( pInsert->vertScales );
212                             mat.rotate( pInsert->dfRotation );
213                             transformations[dCurrentEntHandle] = mat;
214                             break;
215                         }
216                         else
217                         {
218                             assert( 0 );
219                         }
220                     }
221 
222                     if( nullptr != pEntity )
223                     {
224                         addHandle( dCurrentEntHandle, pEntity->getType(), handle );
225                         Matrix mat;
226                         mat.translate( pInsert->vertInsertionPoint );
227                         mat.scale( pInsert->vertScales );
228                         mat.rotate( pInsert->dfRotation );
229                         transformations[dCurrentEntHandle] = mat;
230 
231                         if( pEntity->stCed.bNoLinks )
232                         {
233                             ++dCurrentEntHandle;
234                         }
235                         else
236                         {
237                             dCurrentEntHandle =
238                                 pEntity->stChed.hNextEntity.getAsLong(
239                                     pEntity->stCed.hObjectHandle );
240                         }
241                     }
242                     else
243                     {
244                         assert ( 0 );
245                     }
246                 }
247             }
248         }
249         return;
250     }
251 
252     if( isCommonEntityType( type ) )
253     {
254         if( type == CADObject::IMAGE )
255         {
256             imageHandles.push_back( handle );
257         }
258         else
259         {
260             if( pCADFile->isReadingUnsupportedGeometries() == false )
261             {
262                 if( isSupportedGeometryType( type ) )
263                 {
264                     if( geometryTypes.empty() )
265                     {
266                         geometryTypes.push_back( type );
267                     }
268 
269                     if( find( geometryTypes.begin(), geometryTypes.end(), type ) ==
270                         geometryTypes.end() )
271                     {
272                         geometryTypes.push_back( type );
273                     }
274                     geometryHandles.push_back(
275                                 std::make_pair( handle, cadinserthandle ) );
276                 }
277             }
278             else
279             {
280                 if( geometryTypes.empty() )
281                 {
282                     geometryTypes.push_back( type );
283                 }
284 
285                 if( find( geometryTypes.begin(), geometryTypes.end(), type ) ==
286                     geometryTypes.end() )
287                 {
288                     geometryTypes.push_back( type );
289                 }
290                 geometryHandles.push_back(
291                             std::make_pair( handle, cadinserthandle ) );
292             }
293         }
294     }
295 }
296 
getGeometryCount() const297 size_t CADLayer::getGeometryCount() const
298 {
299     return geometryHandles.size();
300 }
301 
getGeometry(size_t index)302 CADGeometry * CADLayer::getGeometry( size_t index )
303 {
304     auto handleBlockRefPair = geometryHandles[index];
305     CADGeometry * pGeom = pCADFile->GetGeometry( this->getId() - 1,
306                         handleBlockRefPair.first, handleBlockRefPair.second );
307     if( nullptr == pGeom )
308         return nullptr;
309     auto iter = transformations.find( handleBlockRefPair.first );
310     if( iter != transformations.end() )
311     {
312         // transform geometry if nHandle is in transformations
313         pGeom->transform( iter->second );
314     }
315     return pGeom;
316 }
317 
getImageCount() const318 size_t CADLayer::getImageCount() const
319 {
320     return imageHandles.size();
321 }
322 
getImage(size_t index)323 CADImage * CADLayer::getImage( size_t index )
324 {
325     return static_cast<CADImage *>(pCADFile->GetGeometry( this->getId() - 1,
326                                                             imageHandles[index] ));
327 }
328 
addAttribute(const CADObject * pObject)329 bool CADLayer::addAttribute( const CADObject * pObject )
330 {
331     if( nullptr == pObject )
332         return true;
333 
334     auto attrib = static_cast<const CADAttribObject *>(pObject);
335     for( auto i = geometryAttributes.begin(); i != geometryAttributes.end(); ++i )
336     {
337         if( i->first == attrib->stChed.hOwner.getAsLong() )
338         {
339             i->second.insert( make_pair( attrib->sTag, layer_handle ) );
340             return true;
341         }
342     }
343 
344     return false;
345 }
346 
getGeometryTypes()347 std::vector<CADObject::ObjectType> CADLayer::getGeometryTypes()
348 {
349     return geometryTypes;
350 }
351 
getAttributesTags()352 std::unordered_set<std::string> CADLayer::getAttributesTags()
353 {
354     return attributesNames;
355 }
356