├── CMakeLists.txt ├── LICENSE.md ├── README.md ├── STP2X3D ├── CMakeLists.txt ├── Component.cpp ├── Component.h ├── GDT_Item.cpp ├── GDT_Item.h ├── IShape.cpp ├── IShape.h ├── Mesh.cpp ├── Mesh.h ├── Model.cpp ├── Model.h ├── NumTool.h ├── OCCLib.h ├── OCCUtil.cpp ├── OCCUtil.h ├── S2X_Option.cpp ├── S2X_Option.h ├── STEP_Data.cpp ├── STEP_Data.h ├── STEP_Reader.cpp ├── STEP_Reader.h ├── STP2X3D.cpp ├── ShapeType.h ├── StatsPrinter.h ├── StopWatch.cpp ├── StopWatch.h ├── StrTool.h ├── Tessellator.cpp ├── Tessellator.h ├── X3D_Writer.cpp ├── X3D_Writer.h ├── stdafx.cpp └── stdafx.h └── USAGE.md /CMakeLists.txt: -------------------------------------------------------------------------------- 1 | cmake_minimum_required(VERSION 3.12.2) 2 | 3 | project(STP2X3D) 4 | 5 | add_subdirectory(STP2X3D) 6 | -------------------------------------------------------------------------------- /LICENSE.md: -------------------------------------------------------------------------------- 1 | # Terms of Use 2 | 3 | Software produced at NIST is generally not subject to copyright protection in the United States, but may be subject to foreign copyright (as per 17 U.S.C. §105 ). Like data/works, domestic copyright may be held be NIST if copyright is assigned to NIST by a third-party (e.g. contractor). See the [NIST License page][_nistlicense] for more information. 4 | 5 | Distributions of NIST created software, whether in source or compiled form, should include the following licensing statement: 6 | 7 | This software was developed by employees of the 8 | [National Institute of Standards and Technology][_nist] 9 | (NIST), an agency of the Federal Government. Pursuant to 10 | [Title 17, United States Code Section 105][_copy], works of NIST employees are 11 | not subject to copyright protection in the United States and are considered to 12 | be in the [public domain][_pubd]. Permission to freely use, copy, modify, and distribute 13 | this software and its documentation without fee is hereby granted, provided that 14 | this notice and disclaimer of warranty appears in all copies. 15 | 16 | THE SOFTWARE IS PROVIDED 'AS IS' WITHOUT ANY WARRANTY OF ANY KIND, EITHER 17 | EXPRESSED, IMPLIED, OR STATUTORY, INCLUDING, BUT NOT LIMITED TO, ANY WARRANTY 18 | THAT THE SOFTWARE WILL CONFORM TO SPECIFICATIONS, ANY IMPLIED WARRANTIES OF 19 | MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE, AND FREEDOM FROM INFRINGEMENT, 20 | AND ANY WARRANTY THAT THE DOCUMENTATION WILL CONFORM TO THE SOFTWARE, OR ANY 21 | WARRANTY THAT THE SOFTWARE WILL BE ERROR FREE. IN NO EVENT SHALL NIST BE LIABLE 22 | FOR ANY DAMAGES, INCLUDING, BUT NOT LIMITED TO, DIRECT, INDIRECT, SPECIAL OR 23 | CONSEQUENTIAL DAMAGES, ARISING OUT OF, RESULTING FROM, OR IN ANY WAY CONNECTED 24 | WITH THIS SOFTWARE, WHETHER OR NOT BASED UPON WARRANTY, CONTRACT, TORT, OR 25 | OTHERWISE, WHETHER OR NOT INJURY WAS SUSTAINED BY PERSONS OR PROPERTY OR 26 | OTHERWISE, AND WHETHER OR NOT LOSS WAS SUSTAINED FROM, OR AROSE OUT OF THE 27 | RESULTS OF, OR USE OF, THE SOFTWARE OR SERVICES PROVIDED HEREUNDER. 28 | 29 | Distributions of NIST software should also include copyright and licensing 30 | statements of any third-party software that are legally bundled with the code 31 | in compliance with the conditions of those licenses. 32 | 33 | [_copy]: https://www.copyright.gov/title17/92chap1.html#105 34 | [_nist]: https://www.nist.gov 35 | [_pubd]: https://www.copyright.gov/help/faq-definitions.html#public_domain 36 | [_nistlicense]: https://www.nist.gov/topics/data/public-access-nist-research/copyright-fair-use-and-licensing-statements-srd-data-and#software 37 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # NIST STEP to X3D Translator (STP2X3D) 2 | The NIST [STEP to X3D Translator](https://www.nist.gov/services-resources/software/step-x3d-translator) is an open-source software that translates a STEP (ISO 10303) Part 21 file (.stp or .step) to an X3D (ISO/IEC 19776) file (.x3d) or [X3DOM](https://www.x3dom.org/) file (.html). Developed at the National Institute of Standards and Technology (NIST), the software is based on the [Open CASCADE STEP Processor](https://dev.opencascade.org/doc/overview/html/occt_user_guides__step.html) and written in C++. 3 | 4 | ## Prerequisites 5 | - [Open CASCADE Technology](https://www.opencascade.com/content/latest-release) (OCCT) 7.8.0 or higher 6 | - You must [rebuild the OCCT solution](https://dev.opencascade.org/doc/overview/html/build_upgrade__building_occt.html) to regenerate DLL files. 7 | - vc14 or higher (x64) should be selected. 8 | - The complete set of DLL files required for STP2X3D to run is as follows. 9 | - OCCT related: freetype.dll, jemalloc.dll, TKBO.dll, TKBRep.dll, TKCAF.dll, TKCDF.dll, TKDE.dll, TKDESTEP.dll, TKernel.dll, TKG2d.dll, TKG3d.dll, TKGeomAlgo.dll, TKGeomBase.dll, TKHLR.dll, TKLCAF.dll. TKMath.dll, TKMesh.dll, TKPrim.dll, TKService.dll, TKShHealing.dll, TKTopAlgo.dll, TKV3d.dll, TKVCAF.dll, TKXCAF.dll, TKXSBase.dll 10 | - The list of DLL files has been updated since OCCT 7.8.0 especially STEP-related DLL files. 11 | - [jemalloc.dll should be built](https://jemalloc.net/) and included if the memory manager is set to JeMalloc. 12 | - VC++ related: msvcp140.dll, vcruntime140.dll (vcruntime140_1.dll will also be required when vc141 or higher was used to build.) 13 | 14 | ## Build the STEP to X3D Translator 15 | 16 | ### Windows 17 | - Use [CMake](https://cmake.org/) 3.18.4 or higher to build the software. 18 | - vc14 or higher (x64) should be selected for the generator. 19 | - You can also create a new project, include source files, and build the project in Visual Studio. 20 | - Be sure to use Visual Studio 2015 or 2017 due to [std::experimental::filesystem](https://docs.microsoft.com/en-us/cpp/standard-library/filesystem?view=msvc-150). This should be updated later. 21 | - Additional Directories should be added as follows. 22 | - Add "OCCTPath\inc" to Additional Include Directories. 23 | - Add "OCCTPath\win64\vc14\lib" to Additional Library Directories. 24 | 25 | ### Linux (tested Ubuntu 20.10 64bit) 26 | - Use [CMake](https://cmake.org/) 3.12.2 or higher to build the software. 27 | - Modify lines 5-6 of ``STP2X3D/CMakeLists.txt`` to properly set link to OCCT on your local machine. 28 | - Run the following commands from the repository root directory (where this README is located): 29 | ``` 30 | mkdir build 31 | cd build 32 | cmake .. 33 | make 34 | ``` 35 | 36 | ## Usage 37 | - NIST STP2X3D is a command line software. Please check out the [Usage guide](USAGE.md). 38 | 39 | ## Work In Progress 40 | - Support of AP242 Domain Model XML format as input 41 | 42 | ## Contact Information 43 | - Soonjo Kwon, soonjo.kwon@kumoh.ac.kr 44 | - William Z. Bernstein, william.bernstein@afresearchlab.com 45 | 46 | ## Used By 47 | - [NIST STEP File Analyzer and Viewer](https://www.nist.gov/services-resources/software/step-file-analyzer-and-viewer) 48 | 49 | ## Reference 50 | - R. R. Lipman, S. Kwon, 2021, [**STEP File Analyzer and Viewer User Guide (Update 7)**](https://nvlpubs.nist.gov/nistpubs/ams/NIST.AMS.200-12.pdf), *NIST Advanced Manufacturing Series*, 200-12. 51 | 52 | ## Version 53 | 1.50 54 | 55 | ## Disclaimers 56 | [NIST Disclaimer](https://www.nist.gov/disclaimer) 57 | -------------------------------------------------------------------------------- /STP2X3D/CMakeLists.txt: -------------------------------------------------------------------------------- 1 | cmake_minimum_required(VERSION 3.12.2) 2 | 3 | project(STP2X3D) 4 | 5 | set (ENV{CSF_OCCTIncludePath} /usr/local/include/opencascade) 6 | set (ENV{CSF_OCCTLibPath} /usr/local/lib) 7 | 8 | foreach (EnvVar IN ITEMS CSF_OCCTIncludePath CSF_OCCTLibPath) 9 | if ("$ENV{${EnvVar}}" STREQUAL "") 10 | message(WARNING, "Environmental variable '${EnvVar}' is not defined.") 11 | endif () 12 | endforeach () 13 | set(CMAKE_CONFIGURATION_TYPES "Debug;Release" 14 | CACHE STRING "Configuration types" FORCE) 15 | 16 | add_executable(STP2X3D 17 | Component.cpp 18 | Component.h 19 | IShape.cpp 20 | IShape.h 21 | Mesh.cpp 22 | Mesh.h 23 | Model.cpp 24 | Model.h 25 | NumTool.h 26 | OCCLib.h 27 | OCCUtil.cpp 28 | OCCUtil.h 29 | S2X_Option.cpp 30 | S2X_Option.h 31 | StatsPrinter.h 32 | stdafx.cpp 33 | stdafx.h 34 | STEP_Data.cpp 35 | STEP_Data.h 36 | STEP_Reader.cpp 37 | STEP_Reader.h 38 | StopWatch.cpp 39 | StopWatch.h 40 | STP2X3D.cpp 41 | StrTool.h 42 | Tessellator.cpp 43 | Tessellator.h 44 | X3D_Writer.cpp 45 | X3D_Writer.h 46 | ) 47 | # Additional include directories 48 | set_property(TARGET STP2X3D 49 | APPEND PROPERTY INCLUDE_DIRECTORIES 50 | $<$: 51 | $ENV{CSF_OCCTIncludePath}> 52 | $<$: 53 | $ENV{CSF_OCCTIncludePath}> 54 | ) 55 | 56 | target_include_directories(${PROJECT_NAME} PRIVATE $ENV{CSF_OCCTIncludePath}) 57 | target_link_libraries(${PROJECT_NAME} stdc++fs 58 | TKBinL 59 | TKBin 60 | TKBinTObj 61 | TKBinXCAF 62 | TKBool 63 | TKBO 64 | TKBRep 65 | TKCAF 66 | TKCDF 67 | TKernel 68 | TKFeat 69 | TKFillet 70 | TKG2d 71 | TKG3d 72 | TKGeomAlgo 73 | TKGeomBase 74 | TKHLR 75 | TKIGES 76 | TKLCAF 77 | TKMath 78 | TKMesh 79 | TKMeshVS 80 | TKOffset 81 | TKOpenGl 82 | TKPrim 83 | TKRWMesh 84 | TKService 85 | TKShHealing 86 | TKStdL 87 | TKStd 88 | TKSTEP209 89 | TKSTEPAttr 90 | TKSTEPBase 91 | TKSTEP 92 | TKSTL 93 | TKTObj 94 | TKTopAlgo 95 | TKV3d 96 | TKVCAF 97 | TKVRML 98 | TKXCAF 99 | TKXDEIGES 100 | TKXDESTEP 101 | TKXMesh 102 | TKXmlL 103 | TKXml 104 | TKXmlTObj 105 | TKXmlXCAF 106 | TKXSBase ) 107 | 108 | # Preprocessor definitions 109 | target_compile_definitions(STP2X3D PRIVATE 110 | $<$:_UNICODE;_DEBUG;_CONSOLE> 111 | $<$:_UNICODE;NDEBUG;_CONSOLE> 112 | ) 113 | 114 | # SDL check 115 | target_compile_options(STP2X3D PRIVATE 116 | "$<$:/sdl>" 117 | "$<$:/sdl>" 118 | ) 119 | 120 | # Minimal rebuild 121 | if (MSVC) 122 | target_compile_options(STP2X3D PRIVATE 123 | "$<$:/Gm>" 124 | "$<$:/Gm->" 125 | ) 126 | endif () 127 | 128 | # Precompiled header files 129 | if (MSVC) 130 | target_compile_options(STP2X3D PRIVATE 131 | "$<$:/Yu>" 132 | "$<$:/Yu>" 133 | ) 134 | set_property(SOURCE stdafx.cpp 135 | APPEND_STRING PROPERTY COMPILE_FLAGS 136 | "$<$:/Yc> \ 137 | $<$:/Yc>") 138 | endif () 139 | 140 | # Additional library directories 141 | if (MSVC) 142 | target_link_options(STP2X3D PRIVATE 143 | $<$: 144 | /LIBPATH:$ENV{CSF_OCCTLibPath}> 145 | $<$: 146 | /LIBPATH:$ENV{CSF_OCCTLibPath}> 147 | ) 148 | else () 149 | target_link_options(STP2X3D PRIVATE 150 | $<$: 151 | -L$ENV{CSF_OCCTLibPath}> 152 | $<$: 153 | -L$ENV{CSF_OCCTLibPath}> 154 | ) 155 | endif () 156 | -------------------------------------------------------------------------------- /STP2X3D/Component.cpp: -------------------------------------------------------------------------------- 1 | #include "stdafx.h" 2 | #include "Component.h" 3 | #include "IShape.h" 4 | 5 | 6 | Component::Component(const TopoDS_Shape& shape) 7 | : m_parentComponent(nullptr), 8 | m_originalComponent(nullptr), 9 | m_hasUniqueName(false), 10 | m_shape(shape), 11 | m_stepID(-1) 12 | { 13 | } 14 | 15 | Component::~Component(void) 16 | { 17 | Clear(); 18 | } 19 | 20 | void Component::SetUniqueName(const wstring& name) 21 | { 22 | if (name.empty()) 23 | return; 24 | 25 | m_name = name; 26 | m_uniqueName = name; 27 | m_hasUniqueName = true; 28 | } 29 | 30 | void Component::SetOriginalComponent(Component*& originalComp) 31 | { 32 | m_originalComponent = originalComp; 33 | 34 | if (originalComp) 35 | originalComp->AddCopiedComponent(this); 36 | } 37 | 38 | void Component::AddSubComponent(Component*& subComp) 39 | { 40 | m_subComponents.push_back(subComp); 41 | subComp->SetParentComponent(this); 42 | } 43 | 44 | void Component::AddIShape(IShape*& iShape) 45 | { 46 | m_iShapes.push_back(iShape); 47 | iShape->SetComponent(this); 48 | } 49 | 50 | void Component::GetAllComponents(vector& comps) const 51 | { 52 | // Traverse sub components recursively 53 | for (int i = 0; i < GetSubComponentSize(); ++i) 54 | { 55 | Component* subComp = GetSubComponentAt(i); 56 | comps.push_back(subComp); 57 | 58 | subComp->GetAllComponents(comps); 59 | } 60 | } 61 | 62 | void Component::GetLeafComponents(vector& comps) 63 | { 64 | if (IsLeaf()) 65 | comps.push_back(this); 66 | 67 | // Traverse sub components recursively 68 | for (int i = 0; i < GetSubComponentSize(); ++i) 69 | { 70 | Component* subComp = GetSubComponentAt(i); 71 | subComp->GetLeafComponents(comps); 72 | } 73 | } 74 | 75 | void Component::Clean(void) 76 | { 77 | CleanEmptyIShapes(); 78 | CleanEmptySubComponents(); 79 | CleanUselessSubComponents(); 80 | } 81 | 82 | void Component::CleanEmptyIShapes(void) 83 | { 84 | for (int i = 0; i < GetSubComponentSize(); ++i) 85 | { 86 | Component* subComp = GetSubComponentAt(i); 87 | subComp->CleanEmptyIShapes(); 88 | } 89 | 90 | int iShapeSize = GetIShapeSize(); 91 | 92 | for (int i = iShapeSize - 1; i >= 0; --i) 93 | { 94 | IShape* iShape = GetIShapeAt(i); 95 | 96 | // Skip if the shape is not tessellated yet 97 | if (!iShape->IsTessellated()) 98 | continue; 99 | 100 | // Remove empty IShapes after tessellation 101 | if (iShape->IsEmpty()) 102 | { 103 | m_iShapes.erase(m_iShapes.begin() + i); 104 | delete iShape; 105 | } 106 | } 107 | } 108 | 109 | void Component::CleanEmptySubComponents(void) 110 | { 111 | int subCompSize = GetSubComponentSize(); 112 | 113 | for (int i = subCompSize - 1; i >= 0; --i) 114 | { 115 | Component* subComp = GetSubComponentAt(i); 116 | subComp->CleanEmptySubComponents(); 117 | 118 | // Skip if the subcomp is a copy 119 | if (subComp->IsCopy() 120 | && !subComp->GetOriginalComponent()->IsEmpty()) 121 | continue; 122 | 123 | // Remove subcomponents having neither IShape nor child 124 | if (subComp->IsEmpty()) 125 | { 126 | m_subComponents.erase(m_subComponents.begin() + i); 127 | delete subComp; 128 | } 129 | } 130 | } 131 | 132 | void Component::CleanUselessSubComponents(void) 133 | { 134 | for (int i = 0; i < GetSubComponentSize(); ++i) 135 | { 136 | Component* subComp = GetSubComponentAt(i); 137 | subComp->CleanUselessSubComponents(); 138 | } 139 | 140 | // If a component has only one subcomp, remove the subcomp 141 | // Since it has no meaning in terms of structure 142 | if (GetSubComponentSize() == 1) 143 | { 144 | Component* subComp = GetSubComponentAt(0); 145 | 146 | // Skip if the subcomp has a unique name (not empty) 147 | // Since this structure may have been built on purpose 148 | if (subComp->HasUniqueName()) 149 | return; 150 | 151 | // Clear subcomps 152 | ClearSubComponents(); 153 | 154 | // Set multiplied transformation 155 | gp_Trsf trsf = subComp->GetTransformation(); 156 | trsf = trsf.Multiplied(GetTransformation()); 157 | SetTransformation(trsf); 158 | 159 | // Migrate all IShapes of the subcomp to the comp 160 | for (int i = 0; i < subComp->GetIShapeSize(); ++i) 161 | { 162 | IShape* shape = subComp->GetIShapeAt(i); 163 | AddIShape(shape); 164 | } 165 | 166 | // Migrate all subcomps of the subcomp to the comp 167 | for (int i = 0; i < subComp->GetSubComponentSize(); ++i) 168 | { 169 | Component* comp = subComp->GetSubComponentAt(i); 170 | AddSubComponent(comp); 171 | } 172 | 173 | // Delete the subcomp 174 | subComp->ClearIShapes(); 175 | subComp->ClearSubComponents(); 176 | delete subComp; 177 | } 178 | } 179 | 180 | bool Component::IsCopy(void) const 181 | { 182 | if (m_originalComponent) 183 | return true; 184 | 185 | return false; 186 | } 187 | 188 | bool Component::IsAssembly(void) const 189 | { 190 | if (GetSubComponentSize() > 0) 191 | return true; 192 | 193 | return false; 194 | } 195 | 196 | bool Component::IsRoot(void) const 197 | { 198 | if (!m_parentComponent) 199 | return true; 200 | 201 | return false; 202 | } 203 | 204 | bool Component::IsEmpty(void) const 205 | { 206 | if (GetIShapeSize() == 0 207 | && GetSubComponentSize() == 0) 208 | return true; 209 | 210 | return false; 211 | } 212 | 213 | bool Component::IsLeaf(void) const 214 | { 215 | if (GetSubComponentSize() == 0) 216 | return true; 217 | 218 | return false; 219 | } 220 | 221 | bool Component::HasRosette(void) const 222 | { 223 | for (const auto& iShape : m_iShapes) 224 | { 225 | if (iShape->IsRosette()) 226 | return true; 227 | } 228 | 229 | return false; 230 | } 231 | 232 | bool Component::HasSectionCap(void) const 233 | { 234 | for (const auto& iShape : m_iShapes) 235 | { 236 | if (iShape->IsSectionCap()) 237 | return true; 238 | } 239 | 240 | return false; 241 | } 242 | 243 | 244 | const Bnd_Box Component::GetBoundingBox(bool sketch) const 245 | { 246 | Bnd_Box bndBox; 247 | 248 | // Add sub bounding boxes for subComps 249 | for (const auto& subComp : m_subComponents) 250 | { 251 | const gp_Trsf& trsf = subComp->GetTransformation(); 252 | Bnd_Box subBndBox; 253 | 254 | if (subComp->IsCopy()) 255 | subBndBox = subComp->GetOriginalComponent()->GetBoundingBox(sketch).Transformed(trsf); 256 | else 257 | subBndBox = subComp->GetBoundingBox(sketch).Transformed(trsf); 258 | 259 | bndBox.Add(subBndBox); 260 | } 261 | 262 | // Add sub bounding boxes for iShapes 263 | for (const auto& iShape : m_iShapes) 264 | { 265 | bool isSketchGeometry = iShape->IsSketchGeometry(); 266 | 267 | // Skip sketchGeometry when the sketch option is off 268 | if (!sketch 269 | && isSketchGeometry) 270 | continue; 271 | 272 | const TopoDS_Shape& shape = iShape->GetShape(); 273 | 274 | const Bnd_Box& subBndBox = OCCUtil::ComputeBoundingBox(shape); 275 | bndBox.Add(subBndBox); 276 | } 277 | 278 | // Get the finite bounding box (mandatory) 279 | bndBox = bndBox.FinitePart(); 280 | 281 | return bndBox; 282 | } 283 | 284 | TopoDS_Shape Component::GetTransformedShape(void) 285 | { 286 | TopoDS_Shape shape = GetShape(); 287 | TopoDS_Shape copiedShape = OCCUtil::GetCopiedShape(shape); 288 | 289 | gp_Trsf trsf = GetTransformation(); 290 | Component* temp = this; 291 | 292 | while (!temp->IsRoot()) 293 | { 294 | temp = temp->GetParentComponent(); 295 | gp_Trsf tempTrsf = temp->GetTransformation(); 296 | 297 | trsf = trsf.Multiplied(tempTrsf); 298 | } 299 | 300 | TopoDS_Shape trsfShape = OCCUtil::TransformShape(copiedShape, trsf); 301 | 302 | return trsfShape; 303 | } 304 | 305 | void Component::Clear(void) 306 | { 307 | for (auto subComp : m_subComponents) 308 | delete subComp; 309 | 310 | m_subComponents.clear(); 311 | 312 | for (auto iShape : m_iShapes) 313 | delete iShape; 314 | 315 | m_iShapes.clear(); 316 | 317 | //for (auto copiedComp : m_copiedComponents) 318 | // copiedComp->SetOriginalComponent(nullptr); 319 | 320 | m_copiedComponents.clear(); 321 | } -------------------------------------------------------------------------------- /STP2X3D/Component.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | class IShape; 4 | 5 | class Component 6 | { 7 | public: 8 | Component(const TopoDS_Shape& shape); 9 | ~Component(void); 10 | 11 | void SetName(const wstring& name) { m_name = name; } 12 | void SetUniqueName(const wstring& name); 13 | void SetTransformation(const gp_Trsf& trsf) { m_trsf = trsf; } 14 | void SetParentComponent(Component* parentComp) { m_parentComponent = parentComp; } 15 | void SetOriginalComponent(Component*& originalComp); 16 | void SetShape(const TopoDS_Shape& shape) { m_shape = shape; } 17 | 18 | void AddSubComponent(Component*& subComp); 19 | void AddIShape(IShape*& iShape); 20 | 21 | const wstring& GetName(void) const { return m_name; } 22 | const wstring& GetUniqueName(void) const { return m_uniqueName; } 23 | const gp_Trsf& GetTransformation(void) const { return m_trsf; } 24 | const TopoDS_Shape& GetShape(void) const { return m_shape; } 25 | Component* GetParentComponent(void) const { return m_parentComponent; } 26 | Component* GetOriginalComponent(void) const { return m_originalComponent; } 27 | Component* GetSubComponentAt(const int index) const { return m_subComponents[index]; } 28 | IShape* GetIShapeAt(const int index) const { return m_iShapes[index]; } 29 | 30 | const int GetSubComponentSize(void) const { return (int)m_subComponents.size(); } 31 | const int GetIShapeSize(void) const { return (int)m_iShapes.size(); } 32 | 33 | void GetAllComponents(vector& comps) const; 34 | void GetLeafComponents(vector& comps); 35 | const Bnd_Box GetBoundingBox(bool sketch) const; 36 | 37 | TopoDS_Shape GetTransformedShape(void); 38 | 39 | bool HasUniqueName(void) const { return m_hasUniqueName; } 40 | bool IsCopy(void) const; 41 | bool IsAssembly(void) const; 42 | bool IsRoot(void) const; 43 | bool IsEmpty(void) const; 44 | bool IsLeaf(void) const; 45 | bool HasRosette(void) const; 46 | bool HasSectionCap(void) const; 47 | 48 | void Clean(void); 49 | 50 | // SFA-specific 51 | void SetStepID(int stepID) { m_stepID = stepID; } 52 | const int GetStepID(void) const { return m_stepID; } 53 | 54 | protected: 55 | void AddCopiedComponent(Component* copiedComp) { m_copiedComponents.push_back(copiedComp); } 56 | Component* GetCopiedComponentAt(int index) const { return m_copiedComponents[index]; } 57 | int GetCopiedComponentSize(void) const { return (int)m_copiedComponents.size(); } 58 | 59 | protected: 60 | void Clear(void); 61 | 62 | void CleanEmptyIShapes(void); 63 | void CleanEmptySubComponents(void); 64 | void CleanUselessSubComponents(void); 65 | 66 | void ClearSubComponents(void) { m_subComponents.clear(); } 67 | void ClearIShapes(void) { m_iShapes.clear(); } 68 | 69 | private: 70 | wstring m_name; 71 | wstring m_uniqueName; 72 | TopoDS_Shape m_shape; 73 | gp_Trsf m_trsf; 74 | bool m_hasUniqueName; 75 | int m_stepID; 76 | 77 | Component* m_originalComponent; 78 | Component* m_parentComponent; 79 | 80 | vector m_subComponents; 81 | vector m_copiedComponents; 82 | vector m_iShapes; 83 | }; -------------------------------------------------------------------------------- /STP2X3D/GDT_Item.cpp: -------------------------------------------------------------------------------- 1 | #include "stdafx.h" 2 | #include "GDT_Item.h" 3 | #include "Mesh.h" 4 | 5 | GDT_Item::GDT_Item(const wstring& name) 6 | :m_name(name) 7 | { 8 | } 9 | 10 | GDT_Item::~GDT_Item(void) 11 | { 12 | Clear(); 13 | } 14 | 15 | void GDT_Item::AddShape(const TopoDS_Shape& shape) 16 | { 17 | m_shapes.push_back(shape); 18 | m_shapes.erase(unique(m_shapes.begin(), m_shapes.end()), m_shapes.end()); 19 | } 20 | 21 | void GDT_Item::Clear(void) 22 | { 23 | for (auto mesh : m_meshList) 24 | delete mesh; 25 | 26 | m_meshList.clear(); 27 | m_shapes.clear(); 28 | } -------------------------------------------------------------------------------- /STP2X3D/GDT_Item.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | class Mesh; 4 | class IShape; 5 | 6 | class GDT_Item 7 | { 8 | public: 9 | GDT_Item(const wstring& name); 10 | ~GDT_Item(void); 11 | 12 | const wstring& GetName(void) const { return m_name; } 13 | 14 | void AddShape(const TopoDS_Shape& shape); 15 | const TopoDS_Shape& GetShapeAt(int index) const { return m_shapes[index]; } 16 | const int GetShapeSize(void) const { return (int)m_shapes.size(); } 17 | 18 | void AddMesh(Mesh*& mesh) { m_meshList.push_back(mesh); } 19 | Mesh* GetMeshAt(int index) const { return m_meshList[index]; } 20 | const int GetMeshSize(void) const { return (int)m_meshList.size(); } 21 | 22 | protected: 23 | void Clear(void); 24 | 25 | private: 26 | wstring m_name; 27 | vector m_shapes; 28 | vector m_meshList; 29 | }; 30 | -------------------------------------------------------------------------------- /STP2X3D/IShape.cpp: -------------------------------------------------------------------------------- 1 | #include "stdafx.h" 2 | #include "Component.h" 3 | #include "IShape.h" 4 | #include "Mesh.h" 5 | 6 | 7 | IShape::IShape(const TopoDS_Shape& shape) 8 | : m_shape(shape), 9 | m_isTessellated(false), 10 | m_isMultiColored(false), 11 | m_isMultiTransparent(false), 12 | m_isTransparent(false), 13 | m_isFaceSet(false), 14 | m_isRosette(false), 15 | m_isSectionCap(false), 16 | m_isTessSolidModel(false), 17 | m_component(nullptr), 18 | m_globalIndex(0), 19 | m_stepID(-1) 20 | { 21 | // Check if the shape is a face set 22 | if (OCCUtil::HasFace(m_shape)) 23 | m_isFaceSet = true; 24 | } 25 | 26 | IShape::~IShape(void) 27 | { 28 | Clear(); 29 | } 30 | 31 | void IShape::AddColor(const TopoDS_Shape& shape, const Quantity_ColorRGBA& color) 32 | { 33 | int shapeID = OCCUtil::GetID(shape); 34 | //m_shapeIDcolorMap.insert({ shapeID,color }); 35 | 36 | if (m_shapeIDcolorMap.find(shapeID) == m_shapeIDcolorMap.end()) 37 | m_shapeIDcolorMap.insert({ shapeID,color }); 38 | else 39 | m_shapeIDcolorMap.find(shapeID)->second = color; 40 | 41 | CheckColor(color); 42 | } 43 | 44 | const Quantity_ColorRGBA& IShape::GetColor(const TopoDS_Shape& shape) const 45 | { 46 | int shapeID = OCCUtil::GetID(shape); 47 | const Quantity_ColorRGBA& color = m_shapeIDcolorMap.find(shapeID)->second; 48 | 49 | return color; 50 | } 51 | 52 | bool IShape::IsSingleTransparent(void) const 53 | { 54 | if (IsTransparent() 55 | && !IsMultiTransparent()) 56 | return true; 57 | 58 | return false; 59 | } 60 | 61 | bool IShape::IsEmpty(void) const 62 | { 63 | if (GetMeshSize() == 0) 64 | return true; 65 | 66 | return false; 67 | } 68 | 69 | wstring IShape::GetUniqueName(void) const 70 | { 71 | // Get the closest component with a unique name 72 | Component* comp = GetComponent(); 73 | wstring uniqueName = comp->GetUniqueName(); 74 | 75 | while (!comp->IsRoot() 76 | && !comp->HasUniqueName()) 77 | { 78 | comp = comp->GetParentComponent(); 79 | uniqueName = comp->GetUniqueName(); 80 | } 81 | 82 | return uniqueName; 83 | } 84 | 85 | void IShape::CheckColor(const Quantity_ColorRGBA& color) 86 | { 87 | m_colorList.push_back(color); 88 | int colorSize = (int)m_colorList.size(); 89 | 90 | // Check if transparent 91 | if (!m_isTransparent) 92 | { 93 | if (color.Alpha() < 1.0) 94 | m_isTransparent = true; 95 | } 96 | 97 | // Check if multi-colored or multi-transparent 98 | if (colorSize >= 2 99 | && (!m_isMultiColored 100 | || !m_isMultiTransparent)) 101 | { 102 | const Quantity_ColorRGBA& pre = m_colorList[colorSize - 2]; 103 | const Quantity_ColorRGBA& cur = m_colorList[colorSize - 1]; 104 | 105 | if (!m_isMultiColored 106 | && pre.GetRGB() != cur.GetRGB()) 107 | m_isMultiColored = true; 108 | 109 | if (!m_isMultiTransparent 110 | && pre.Alpha() != cur.Alpha()) 111 | m_isMultiTransparent = true; 112 | } 113 | } 114 | 115 | void IShape::Clear(void) 116 | { 117 | for (auto mesh : m_meshList) 118 | delete mesh; 119 | 120 | m_meshList.clear(); 121 | m_colorList.clear(); 122 | m_shapeIDcolorMap.clear(); 123 | } -------------------------------------------------------------------------------- /STP2X3D/IShape.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | class Component; 4 | class Mesh; 5 | 6 | class IShape 7 | { 8 | public: 9 | IShape(const TopoDS_Shape& shape); 10 | ~IShape(void); 11 | 12 | void SetName(const wstring& name) { m_name = name; } 13 | void SetComponent(Component* comp) { m_component = comp; } 14 | void SetGlobalIndex(int globalIndex) { m_globalIndex = globalIndex; } 15 | void SetTessellated(bool isTessellated) { m_isTessellated = isTessellated; } 16 | void SetRosette(bool isRosette) { m_isRosette = isRosette; } 17 | void SetSectionCap(bool isSectionCap) { m_isSectionCap = isSectionCap; } 18 | void SetTessSolidModel(bool isTessSolidModel) { m_isTessSolidModel = isTessSolidModel; } 19 | void AddColor(const TopoDS_Shape& shape, const Quantity_ColorRGBA& color); 20 | void AddMesh(Mesh*& mesh) { m_meshList.push_back(mesh); } 21 | 22 | const wstring& GetName(void) const { return m_name; } 23 | Component* GetComponent(void) const { return m_component; } 24 | const TopoDS_Shape& GetShape(void) const { return m_shape; } 25 | const Quantity_ColorRGBA& GetColor(const TopoDS_Shape& shape) const; 26 | const Quantity_ColorRGBA& GetColor(void) const { return m_colorList.at(0); } 27 | 28 | Mesh* GetMeshAt(int index) const { return m_meshList[index]; } 29 | const int GetGlobalIndex(void) const { return m_globalIndex; } 30 | 31 | const int GetMeshSize(void) const { return (int)m_meshList.size(); } 32 | 33 | bool IsMultiColored(void) const { return m_isMultiColored; } 34 | bool IsMultiTransparent(void) const { return m_isMultiTransparent; } 35 | bool IsSingleTransparent(void) const; 36 | bool IsTransparent(void) const { return m_isTransparent; } 37 | bool IsTessellated(void) const { return m_isTessellated; } 38 | 39 | bool IsFaceSet(void) const { return m_isFaceSet; } 40 | bool IsSketchGeometry(void) const { return !m_isFaceSet; } 41 | 42 | bool IsRosette(void) const { return m_isRosette; } 43 | bool IsSectionCap(void) const { return m_isSectionCap; } 44 | 45 | bool IsTessSolidModel(void) const { return m_isTessSolidModel; } 46 | 47 | bool IsEmpty(void) const; 48 | 49 | // SFA-specific 50 | wstring GetUniqueName(void) const; 51 | 52 | void SetStepID(int stepID) { m_stepID = stepID; } 53 | const int GetStepID(void) const { return m_stepID; } 54 | 55 | 56 | protected: 57 | void CheckColor(const Quantity_ColorRGBA& color); 58 | void Clear(void); 59 | 60 | private: 61 | wstring m_name; 62 | TopoDS_Shape m_shape; 63 | int m_globalIndex; 64 | int m_stepID; 65 | 66 | bool m_isMultiColored; 67 | bool m_isMultiTransparent; 68 | bool m_isTransparent; 69 | bool m_isTessellated; 70 | bool m_isFaceSet; 71 | bool m_isRosette; 72 | bool m_isSectionCap; 73 | bool m_isTessSolidModel; 74 | 75 | Component* m_component; 76 | 77 | vector m_meshList; 78 | vector m_colorList; 79 | unordered_map m_shapeIDcolorMap; 80 | }; -------------------------------------------------------------------------------- /STP2X3D/Mesh.cpp: -------------------------------------------------------------------------------- 1 | #include "stdafx.h" 2 | #include "Mesh.h" 3 | 4 | 5 | Mesh::Mesh(const TopoDS_Shape& shape) 6 | : m_shape(shape) 7 | { 8 | } 9 | 10 | Mesh::~Mesh(void) 11 | { 12 | Clear(); 13 | } 14 | 15 | void Mesh::AddFaceIndex(int v1, int v2, int v3) 16 | { 17 | Index m_index; 18 | m_index.push_back(v1); 19 | m_index.push_back(v2); 20 | m_index.push_back(v3); 21 | 22 | m_faceIndexes.push_back(m_index); 23 | } 24 | 25 | void Mesh::AddNormalIndex(int v1, int v2, int v3) 26 | { 27 | Index m_index; 28 | m_index.push_back(v1); 29 | m_index.push_back(v2); 30 | m_index.push_back(v3); 31 | 32 | m_normalIndexes.push_back(m_index); 33 | } 34 | 35 | void Mesh::AddEdgeIndex(Index edgeIndex) 36 | { 37 | m_edgeIndexes.push_back(edgeIndex); 38 | } 39 | 40 | bool Mesh::IsEmpty(void) const 41 | { 42 | if (m_coordinates.empty()) 43 | return true; 44 | 45 | return false; 46 | } 47 | 48 | void Mesh::Clear(void) 49 | { 50 | for (auto faceIndex : m_faceIndexes) 51 | faceIndex.clear(); 52 | 53 | for (auto normalIndex : m_normalIndexes) 54 | normalIndex.clear(); 55 | 56 | for (auto edgeIndex : m_edgeIndexes) 57 | edgeIndex.clear(); 58 | 59 | m_faceIndexes.clear(); 60 | m_normalIndexes.clear(); 61 | m_edgeIndexes.clear(); 62 | m_coordinates.clear(); 63 | m_normals.clear(); 64 | } -------------------------------------------------------------------------------- /STP2X3D/Mesh.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | typedef vector Index; 4 | 5 | class Mesh 6 | { 7 | public: 8 | Mesh(const TopoDS_Shape& shape); 9 | ~Mesh(void); 10 | 11 | void AddFaceIndex(int v1, int v2, int v3); 12 | void AddNormalIndex(int v1, int v2, int v3); 13 | void AddEdgeIndex(Index edgeIndex); 14 | void AddCoordinate(const gp_XYZ& coord) { m_coordinates.push_back(coord); } 15 | void AddNormal(const gp_XYZ& norm) { m_normals.push_back(norm); } 16 | 17 | const TopoDS_Shape& GetShape(void) const { return m_shape; } 18 | const Index& GetFaceIndexAt(int index) const { return m_faceIndexes[index]; } 19 | const Index& GetNormalIndexAt(int index) const { return m_normalIndexes[index]; } 20 | const Index& GetEdgeIndexAt(int index) const { return m_edgeIndexes[index]; } 21 | const gp_XYZ& GetCoordinateAt(int index) const { return m_coordinates[index]; } 22 | const gp_XYZ& GetNormalAt(int index) const { return m_normals[index]; } 23 | 24 | const int GetFaceIndexSize(void) const { return (int)m_faceIndexes.size(); } 25 | const int GetNormalIndexSize(void) const { return (int)m_normalIndexes.size(); } 26 | const int GetEdgeIndexSize(void) const { return (int)m_edgeIndexes.size(); } 27 | const int GetCoordinateSize(void) const { return (int)m_coordinates.size(); } 28 | const int GetNormalSize(void) const { return (int)m_normals.size(); } 29 | 30 | bool IsEmpty(void) const; 31 | 32 | protected: 33 | void Clear(void); 34 | 35 | private: 36 | TopoDS_Shape m_shape; 37 | 38 | vector m_coordinates; 39 | vector m_normals; 40 | 41 | vector m_faceIndexes; 42 | vector m_normalIndexes; 43 | vector m_edgeIndexes; 44 | }; -------------------------------------------------------------------------------- /STP2X3D/Model.cpp: -------------------------------------------------------------------------------- 1 | #include "stdafx.h" 2 | #include "Model.h" 3 | #include "Component.h" 4 | #include "IShape.h" 5 | #include "GDT_Item.h" 6 | 7 | Model::Model(void) 8 | { 9 | } 10 | 11 | Model::~Model(void) 12 | { 13 | Clear(); 14 | } 15 | 16 | void Model::GetAllComponents(vector& comps) const 17 | { 18 | for (const auto& rootComp : m_rootComponents) 19 | { 20 | comps.push_back(rootComp); 21 | rootComp->GetAllComponents(comps); 22 | } 23 | } 24 | 25 | void Model::GetLeafComponents(vector& comps) const 26 | { 27 | for (const auto& rootComp : m_rootComponents) 28 | { 29 | rootComp->GetLeafComponents(comps); 30 | } 31 | } 32 | 33 | const Bnd_Box Model::GetBoundingBox(bool sketch) const 34 | { 35 | Bnd_Box bndBox; 36 | 37 | for (const auto& rootComp : m_rootComponents) 38 | { 39 | const Bnd_Box& subBndBox = rootComp->GetBoundingBox(sketch); 40 | bndBox.Add(subBndBox); 41 | } 42 | 43 | return bndBox; 44 | } 45 | 46 | const ShapeType Model::GetShapeType(void) const 47 | { 48 | vector comps; 49 | GetAllComponents(comps); 50 | 51 | int shapeCount = 0; 52 | int sketchCount = 0; 53 | 54 | ShapeType shapeType = ShapeType::Face_Geom; 55 | 56 | for (const auto& comp : comps) 57 | { 58 | for (int i = 0; i < comp->GetIShapeSize(); ++i) 59 | { 60 | IShape* iShape = comp->GetIShapeAt(i); 61 | shapeCount++; 62 | 63 | if (iShape->IsSketchGeometry()) 64 | sketchCount++; 65 | } 66 | } 67 | 68 | comps.clear(); 69 | 70 | if (sketchCount > 0) 71 | { 72 | if (shapeCount == sketchCount) 73 | shapeType = ShapeType::Sketch_Geom; 74 | else 75 | shapeType = ShapeType::Hybrid_Geom; 76 | } 77 | 78 | return shapeType; 79 | } 80 | 81 | bool Model::IsEmpty(void) const 82 | { 83 | int size = 0; 84 | 85 | for (const auto& rootComp : m_rootComponents) 86 | { 87 | if (rootComp->IsEmpty()) 88 | size++; 89 | } 90 | 91 | if (size == (int)m_rootComponents.size()) 92 | return true; 93 | 94 | return false; 95 | } 96 | 97 | void Model::Update(void) 98 | { 99 | Clean(); 100 | UpdateNames(); 101 | } 102 | 103 | GDT_Item* Model::GetGDTByName(wstring name) const 104 | { 105 | for (const auto& gdt : m_gdts) 106 | { 107 | if (name == gdt->GetName()) 108 | return gdt; 109 | } 110 | 111 | return nullptr; 112 | } 113 | 114 | 115 | void Model::Clean(void) 116 | { 117 | int rootCompSize = GetRootComponentSize(); 118 | 119 | for (int i = rootCompSize - 1; i >= 0; --i) 120 | { 121 | Component* rootComp = GetRootComponentAt(i); 122 | 123 | if (rootComp->IsEmpty()) 124 | { 125 | m_rootComponents.erase(m_rootComponents.begin() + i); 126 | delete rootComp; 127 | } 128 | else 129 | rootComp->Clean(); 130 | } 131 | } 132 | 133 | void Model::UpdateNames(void) const 134 | { 135 | UpdateComponentNames(); 136 | UpdateIShapeNames(); 137 | UpdateGlobalIShapeIndex(); 138 | } 139 | 140 | void Model::UpdateComponentNames(void) const 141 | { 142 | wstring connector = L"_"; // Character connecting Group name and order 143 | 144 | // Make all components' names unique to avoid conflict 145 | vector comps; 146 | GetAllComponents(comps); 147 | 148 | map tmpNameCountMap, nameCountMap; 149 | 150 | // Count all component names first 151 | for (const auto& comp : comps) 152 | { 153 | wstring compName = comp->GetName(); 154 | 155 | // Skip if the name is empty 156 | if (compName.empty()) 157 | continue; 158 | 159 | if (tmpNameCountMap.find(compName) == tmpNameCountMap.end()) 160 | tmpNameCountMap.insert({ compName, 1 }); 161 | else 162 | { 163 | int count = tmpNameCountMap[compName]; 164 | count++; 165 | tmpNameCountMap[compName] = count; 166 | } 167 | } 168 | 169 | // Update all component names 170 | for (const auto& comp : comps) 171 | { 172 | wstring compName = comp->GetName(); 173 | 174 | // Skip if the name is empty 175 | if (compName.empty()) 176 | continue; 177 | 178 | // Skip if the name is one and only 179 | if (tmpNameCountMap.find(compName)->second == 1) 180 | continue; 181 | 182 | if (nameCountMap.find(compName) == nameCountMap.end()) 183 | { 184 | nameCountMap.insert({ compName, 1 }); 185 | comp->SetName(compName + connector + to_wstring(1)); 186 | } 187 | else 188 | { 189 | int count = nameCountMap[compName]; 190 | count++; 191 | nameCountMap[compName] = count; 192 | comp->SetName(compName + connector + to_wstring(count)); 193 | } 194 | } 195 | 196 | tmpNameCountMap.clear(); 197 | nameCountMap.clear(); 198 | 199 | // Update subcomponent names 200 | for (const auto& comp : comps) 201 | { 202 | if (comp->IsRoot() 203 | && !comp->HasUniqueName()) 204 | comp->SetName(L"unnamed"); 205 | 206 | wstring compName = comp->GetName(); 207 | int compIndex = 1; 208 | 209 | for (int i = 0; i < comp->GetSubComponentSize(); ++i) 210 | { 211 | Component* subComp = comp->GetSubComponentAt(i); 212 | 213 | if (subComp->HasUniqueName()) 214 | continue; 215 | 216 | // Do not count wire set (SFA-specific) 217 | if (subComp->GetIShapeSize() == 1 218 | && subComp->GetIShapeAt(0)->IsSketchGeometry()) 219 | continue; 220 | 221 | subComp->SetName(compName + connector + to_wstring(compIndex)); 222 | compIndex++; 223 | } 224 | } 225 | 226 | comps.clear(); 227 | } 228 | 229 | void Model::UpdateIShapeNames(void) const 230 | { 231 | wstring connector = L"_"; // Character connecting IShape name and order 232 | 233 | vector comps; 234 | GetAllComponents(comps); 235 | 236 | for (const auto& comp : comps) 237 | { 238 | wstring compName = comp->GetName(); 239 | int shapeIndex = 1; 240 | 241 | for (int i = 0; i < comp->GetIShapeSize(); ++i) 242 | { 243 | IShape* iShape = comp->GetIShapeAt(i); 244 | 245 | if (iShape->IsSketchGeometry() 246 | || iShape->IsRosette() 247 | || iShape->IsSectionCap()) 248 | continue; 249 | 250 | iShape->SetName(compName + connector + to_wstring(shapeIndex)); 251 | shapeIndex++; 252 | } 253 | } 254 | 255 | comps.clear(); 256 | } 257 | 258 | void Model::UpdateGlobalIShapeIndex(void) const 259 | { 260 | vector comps; 261 | GetAllComponents(comps); 262 | 263 | // Global shape index for Coordinate DEF/USE 264 | int globalIndex = 1; 265 | 266 | // Update names and indexes of iShapes at every update 267 | for (const auto& comp : comps) 268 | { 269 | for (int i = 0; i < comp->GetIShapeSize(); ++i) 270 | { 271 | IShape* iShape = comp->GetIShapeAt(i); 272 | 273 | if (iShape->IsSketchGeometry()) 274 | continue; 275 | 276 | iShape->SetGlobalIndex(globalIndex); 277 | globalIndex++; 278 | } 279 | } 280 | 281 | comps.clear(); 282 | } 283 | 284 | void Model::Clear(void) 285 | { 286 | for (auto rootComp : m_rootComponents) 287 | delete rootComp; 288 | 289 | m_rootComponents.clear(); 290 | 291 | for (auto gdt : m_gdts) 292 | delete gdt; 293 | 294 | m_gdts.clear(); 295 | } -------------------------------------------------------------------------------- /STP2X3D/Model.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | class Component; 4 | class GDT_Item; 5 | 6 | class Model 7 | { 8 | public: 9 | Model(void); 10 | ~Model(void); 11 | 12 | void AddRootComponent(Component*& comp) { m_rootComponents.push_back(comp); } 13 | Component* GetRootComponentAt(int index) const { return m_rootComponents[index]; } 14 | const int GetRootComponentSize(void) const { return (int)m_rootComponents.size(); } 15 | 16 | void GetAllComponents(vector& comps) const; 17 | void GetLeafComponents(vector& comps) const; 18 | const Bnd_Box GetBoundingBox(bool sketch) const; 19 | const ShapeType GetShapeType(void) const; 20 | 21 | bool IsEmpty(void) const; 22 | 23 | void Update(void); 24 | void Clear(void); 25 | 26 | // GD&T 27 | void AddGDT(GDT_Item*& gdt_item) { m_gdts.push_back(gdt_item); } 28 | const int GetGDTSize(void) const { return (int)m_gdts.size(); } 29 | GDT_Item* GetGDTAt(int index) const { return m_gdts[index]; } 30 | GDT_Item* GetGDTByName(wstring name) const; 31 | 32 | 33 | protected: 34 | void Clean(void); 35 | 36 | void UpdateNames(void) const; 37 | void UpdateComponentNames(void) const; 38 | void UpdateIShapeNames(void) const; 39 | void UpdateGlobalIShapeIndex(void) const; 40 | 41 | private: 42 | vector m_rootComponents; 43 | vector m_gdts; 44 | }; -------------------------------------------------------------------------------- /STP2X3D/NumTool.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include "StrTool.h" 4 | 5 | class NumTool 6 | { 7 | public: 8 | 9 | static const string DoubleToString(double val) 10 | { 11 | // Round up 12 | double digit = 1.e4; // e4: 4th decimal digit, e-4: 4th digit 13 | double val_ru = RoundUp(val, digit); 14 | 15 | // Write float to string 16 | stringstream real_value_ss; 17 | real_value_ss << val_ru; 18 | 19 | string str = real_value_ss.str(); 20 | 21 | // -0 -> 0 22 | if (str == "-0" 23 | || str == "-0.0") 24 | str = "0"; 25 | 26 | // 0.xxx -> .xxx 27 | if (str.find("0.") == 0) 28 | str = str.substr(str.find("."), str.length() - 1); 29 | 30 | // -0.xxx -> -.xxx 31 | if (str.find("-0.") == 0) 32 | str = "-" + str.substr(str.find("."), str.length() - 1); 33 | 34 | return str; 35 | } 36 | 37 | static const wstring DoubleToWString(double val) 38 | { 39 | string str = DoubleToString(val); 40 | wstring wstr = StrTool::str2wstr(str); 41 | 42 | return wstr; 43 | } 44 | 45 | static const double RoundUp(double val, const double digit) 46 | { 47 | double val_ru = floor(abs(val) * digit + 0.5); 48 | val_ru = val_ru / digit; 49 | 50 | if (val < 0.0) 51 | val_ru = (-1) * val_ru; 52 | 53 | return val_ru; 54 | } 55 | 56 | }; -------------------------------------------------------------------------------- /STP2X3D/OCCLib.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #pragma comment(lib, "TKBO.lib") 4 | #pragma comment(lib, "TKBrep.lib") 5 | #pragma comment(lib, "TKCAF.lib") 6 | #pragma comment(lib, "TKCDF.lib") 7 | 8 | #pragma comment(lib, "TKDE.lib") 9 | #pragma comment(lib, "TKDESTEP.lib") 10 | #pragma comment(lib, "TKernel.lib") 11 | 12 | #pragma comment(lib, "TKG2d.lib") 13 | #pragma comment(lib, "TKG3d.lib") 14 | 15 | #pragma comment(lib, "TKGeomAlgo.lib") 16 | #pragma comment(lib, "TKGeomBase.lib") 17 | 18 | #pragma comment(lib, "TKHLR.lib") 19 | #pragma comment(lib, "TKLCAF.lib") 20 | 21 | #pragma comment(lib, "TKMath.lib") 22 | #pragma comment(lib, "TKMesh.lib") 23 | 24 | #pragma comment(lib, "TKPrim.lib") 25 | #pragma comment(lib, "TKService.lib") 26 | #pragma comment(lib, "TKShHealing.lib") 27 | #pragma comment(lib, "TKTopAlgo.lib") 28 | 29 | #pragma comment(lib, "TKV3d.lib") 30 | #pragma comment(lib, "TKVCAF.lib") 31 | #pragma comment(lib, "TKXCAF.lib") 32 | 33 | #pragma comment(lib, "TKXSBase.lib") 34 | 35 | #include 36 | #include 37 | #include 38 | 39 | #include 40 | #include 41 | #include 42 | #include 43 | 44 | #include 45 | #include 46 | #include 47 | #include 48 | #include 49 | #include 50 | #include 51 | #include 52 | #include 53 | #include 54 | #include 55 | #include 56 | #include 57 | #include 58 | #include 59 | #include 60 | #include 61 | #include 62 | #include 63 | #include 64 | #include 65 | 66 | #include 67 | 68 | #include 69 | #include 70 | #include 71 | #include 72 | #include 73 | #include 74 | #include 75 | #include 76 | #include 77 | #include 78 | #include 79 | #include 80 | #include 81 | #include 82 | #include 83 | #include 84 | #include 85 | #include 86 | 87 | #include 88 | #include 89 | #include 90 | 91 | #include 92 | #include 93 | 94 | #include 95 | 96 | #include 97 | #include 98 | #include 99 | 100 | #include 101 | #include 102 | #include 103 | #include 104 | #include 105 | #include 106 | #include 107 | #include 108 | #include 109 | 110 | #include 111 | #include 112 | #include 113 | #include 114 | #include 115 | #include 116 | #include 117 | #include 118 | #include 119 | #include 120 | #include 121 | #include 122 | #include 123 | #include 124 | #include 125 | #include 126 | #include 127 | #include 128 | #include 129 | #include 130 | #include 131 | #include 132 | 133 | #include 134 | #include 135 | 136 | #include 137 | #include 138 | #include 139 | #include 140 | #include 141 | #include 142 | #include 143 | 144 | #include 145 | #include 146 | 147 | //#include 148 | //#include 149 | //#include 150 | #include 151 | #include 152 | #include 153 | #include -------------------------------------------------------------------------------- /STP2X3D/OCCUtil.cpp: -------------------------------------------------------------------------------- 1 | #include "stdafx.h" 2 | #include "OCCUtil.h" 3 | 4 | 5 | namespace OCCUtil 6 | { 7 | const int GetID(const TopoDS_Shape& shape) 8 | { 9 | //const int id = shape.HashCode(INT_MAX); 10 | const int id = static_cast(std::hash{}(shape)); 11 | 12 | return id; 13 | } 14 | 15 | const Bnd_Box ComputeBoundingBox(const TopoDS_Shape& shape) 16 | { 17 | Bnd_Box bndBox; 18 | BRepBndLib::Add(shape, bndBox); 19 | 20 | return bndBox; 21 | } 22 | 23 | double ComputeVolume(const TopoDS_Shape& shape) 24 | { 25 | GProp_GProps System; 26 | BRepGProp::VolumeProperties(shape, System); 27 | 28 | double volume = System.Mass(); 29 | 30 | return volume; 31 | } 32 | 33 | void RemoveFreeWires(TopoDS_Shape shape) 34 | { 35 | BRepTools::Clean(shape); 36 | BRep_Builder builder; 37 | 38 | for (TopoDS_Iterator exp(shape); exp.More(); exp.Next()) 39 | { 40 | TopoDS_Shape subShape = exp.Value(); 41 | TopAbs_ShapeEnum subShapeType = subShape.ShapeType(); 42 | 43 | if (subShapeType == TopAbs_COMPOUND) 44 | { 45 | RemoveFreeWires(subShape); 46 | } 47 | else if (subShapeType != TopAbs_COMPSOLID 48 | && subShapeType != TopAbs_SOLID 49 | && subShapeType != TopAbs_SHELL) 50 | { 51 | // wires or edges or vertices 52 | builder.Remove(shape, subShape); 53 | } 54 | } 55 | } 56 | 57 | TopoDS_Shape GetCopiedShape(TopoDS_Shape shape) 58 | { 59 | BRepBuilderAPI_Copy copier(shape); 60 | const TopoDS_Shape copiedShape = copier.Shape(); 61 | 62 | return copiedShape; 63 | } 64 | 65 | bool HasFace(const TopoDS_Shape& shape) 66 | { 67 | TopExp_Explorer ExpFace; 68 | for (ExpFace.Init(shape, TopAbs_FACE); ExpFace.More(); ExpFace.Next()) 69 | return true; 70 | 71 | return false; 72 | } 73 | 74 | bool HasEdge(const TopoDS_Shape& shape) 75 | { 76 | TopExp_Explorer ExpEdge; 77 | for (ExpEdge.Init(shape, TopAbs_EDGE); ExpEdge.More(); ExpEdge.Next()) 78 | return true; 79 | 80 | return false; 81 | } 82 | 83 | bool IsFreeEdge(const TopoDS_Shape& shape) 84 | { 85 | if (!HasFace(shape) 86 | && HasEdge(shape)) 87 | return true; 88 | 89 | return false; 90 | } 91 | 92 | bool HasWire(const TopoDS_Shape& shape) 93 | { 94 | TopExp_Explorer ExpWire; 95 | for (ExpWire.Init(shape, TopAbs_WIRE); ExpWire.More(); ExpWire.Next()) 96 | return true; 97 | 98 | return false; 99 | } 100 | 101 | TopoDS_Shape TransformShape(TopoDS_Shape shape, gp_Trsf trsf) 102 | { 103 | // Note that a shape loses its color after transformation 104 | BRepBuilderAPI_Transform transform(shape, trsf); 105 | TopoDS_Shape trsfShape = transform.Shape(); 106 | 107 | return trsfShape; 108 | } 109 | 110 | bool TessellateShape(const TopoDS_Shape& shape, double linearDeflection, bool isRelative, double angularDeflection, bool isParallel) 111 | { 112 | BRepTools::Clean(shape); 113 | BRepMesh_IncrementalMesh bMesh(shape, linearDeflection, isRelative, angularDeflection, isParallel); 114 | 115 | return bMesh.IsDone(); 116 | } 117 | 118 | bool IsTranslated(const gp_Trsf& transform) 119 | { 120 | const gp_XYZ& trans = transform.TranslationPart(); 121 | 122 | if (!(trans.X() == 0.0 123 | && trans.Y() == 0.0 124 | && trans.Z() == 0.0)) 125 | return true; 126 | 127 | return false; 128 | } 129 | 130 | bool IsRotated(const gp_Trsf& transform) 131 | { 132 | gp_Vec rotAxis; 133 | double rotAngle = 0.0; 134 | transform.GetRotation().GetVectorAndAngle(rotAxis, rotAngle); 135 | 136 | if (rotAngle != 0.0) 137 | return true; 138 | 139 | return false; 140 | } 141 | 142 | bool IsTransformed(const gp_Trsf& transform) 143 | { 144 | if (IsTranslated(transform) 145 | || IsRotated(transform)) 146 | return true; 147 | 148 | return false; 149 | } 150 | 151 | double GetDeflection(const TopoDS_Shape& shape) 152 | { 153 | Bnd_Box bndBox = ComputeBoundingBox(shape); 154 | 155 | bndBox = bndBox.FinitePart(); 156 | 157 | gp_Pnt minPnt = bndBox.CornerMin(); 158 | gp_Pnt maxPnt = bndBox.CornerMax(); 159 | 160 | double deviationCoefficient = 0.001; 161 | 162 | double deflection = Prs3d::GetDeflection(Graphic3d_Vec3d(minPnt.X(), minPnt.Y(), minPnt.Z()), Graphic3d_Vec3d(maxPnt.X(), maxPnt.Y(), maxPnt.Z()), deviationCoefficient); 163 | 164 | return Max(deflection, Precision::Confusion()); 165 | } 166 | } -------------------------------------------------------------------------------- /STP2X3D/OCCUtil.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | namespace OCCUtil 4 | { 5 | // Get unique id for shape 6 | const int GetID(const TopoDS_Shape& shape); 7 | 8 | // Compute bounding box of a shape 9 | const Bnd_Box ComputeBoundingBox(const TopoDS_Shape& shape); 10 | 11 | // Compute volue of a shape 12 | double ComputeVolume(const TopoDS_Shape& shape); 13 | 14 | // Remove free wires, edges, and vertices not beloing to solids or shells 15 | void RemoveFreeWires(TopoDS_Shape shape); 16 | 17 | // Copy and return the shape 18 | TopoDS_Shape GetCopiedShape(TopoDS_Shape shape); 19 | 20 | // Check if the shape has faces 21 | bool HasFace(const TopoDS_Shape& shape); 22 | 23 | // Check if the shape has edges 24 | bool HasEdge(const TopoDS_Shape& shape); 25 | 26 | // Check if the shape is free edges 27 | bool IsFreeEdge(const TopoDS_Shape& shape); 28 | 29 | // Check if the shape has wires 30 | bool HasWire(const TopoDS_Shape& shape); 31 | 32 | // Transform a shape 33 | TopoDS_Shape TransformShape(TopoDS_Shape shape, gp_Trsf trsf); 34 | 35 | // Tessellate a shape 36 | bool TessellateShape(const TopoDS_Shape& shape, double linearDeflection, bool isRelative, double angularDeflection, bool isParallel); 37 | 38 | // Check if translated 39 | bool IsTranslated(const gp_Trsf& transform); 40 | 41 | // Check if rotated 42 | bool IsRotated(const gp_Trsf& transform); 43 | 44 | // Check if transformed 45 | bool IsTransformed(const gp_Trsf& transform); 46 | 47 | // Get the relative deflection for a given shape 48 | double GetDeflection(const TopoDS_Shape& shape); 49 | } -------------------------------------------------------------------------------- /STP2X3D/S2X_Option.cpp: -------------------------------------------------------------------------------- 1 | #include "stdafx.h" 2 | #include "S2X_Option.h" 3 | 4 | 5 | S2X_Option::S2X_Option() 6 | : m_input(L""), 7 | m_output(L""), 8 | m_normal(false), 9 | m_color(true), 10 | m_edge(false), 11 | m_sketch(true), 12 | m_html(false), 13 | m_tessellation(false), 14 | m_quality(5.0), 15 | m_batch(-1), 16 | m_SFA(true), 17 | m_gdt(false), 18 | m_rosette(false), 19 | m_cap(false), 20 | m_tessSolid(true) 21 | { 22 | } 23 | 24 | S2X_Option::~S2X_Option() 25 | { 26 | } 27 | 28 | void S2X_Option::SetNormal(const int& normal) 29 | { 30 | if (normal == 0) 31 | m_normal = false; 32 | else 33 | m_normal = true; 34 | } 35 | 36 | void S2X_Option::SetColor(const int& color) 37 | { 38 | if (color == 0) 39 | m_color = false; 40 | else 41 | m_color = true; 42 | } 43 | 44 | void S2X_Option::SetEdge(const int& edge) 45 | { 46 | if (edge == 0) 47 | m_edge = false; 48 | else 49 | m_edge = true; 50 | } 51 | 52 | void S2X_Option::SetSketch(const int& sketch) 53 | { 54 | if (sketch == 0) 55 | m_sketch = false; 56 | else 57 | m_sketch = true; 58 | } 59 | 60 | void S2X_Option::SetHtml(const int& html) 61 | { 62 | if (html == 0) 63 | m_html = false; 64 | else 65 | m_html = true; 66 | } 67 | 68 | void S2X_Option::SetTessellation(const int& tessellation) 69 | { 70 | if (tessellation == 0) 71 | m_tessellation = false; 72 | else 73 | m_tessellation = true; 74 | } 75 | 76 | const wstring S2X_Option::Output(void) 77 | { 78 | if (m_output.empty()) 79 | m_output = m_input.substr(0, m_input.find_last_of(L".")); 80 | 81 | if (m_html) 82 | m_output.append(L".html"); 83 | else 84 | m_output.append(L".x3d"); 85 | 86 | return m_output; 87 | } -------------------------------------------------------------------------------- /STP2X3D/S2X_Option.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | class S2X_Option 4 | { 5 | public: 6 | S2X_Option(); 7 | ~S2X_Option(); 8 | 9 | void SetInput(const wstring& input) { m_input = input; } 10 | void SetOutput(const wstring& output) { m_output = output; } 11 | void SetNormal(const int& normal); 12 | void SetColor(const int& color); 13 | void SetEdge(const int& edge); 14 | void SetSketch(const int& sketch); 15 | void SetHtml(const int& html); 16 | void SetTessellation(const int& tessellation); 17 | void SetQuality(const double& quality) { m_quality = quality; } 18 | void SetBatch(const int& batch) { m_batch = batch; } 19 | void SetSFA(bool sfa) { m_SFA = sfa; } 20 | void SetGDT(bool gdt) { m_gdt = gdt; } 21 | void SetRosette(bool rosette) { m_rosette = rosette; } 22 | void SetSectionCap(bool cap) { m_cap = cap; } 23 | void SetTessSolid(bool tessSolid) { m_tessSolid = tessSolid; } 24 | 25 | const wstring& Input(void) const { return m_input; } 26 | const wstring Output(void); 27 | bool Normal(void) const { return m_normal; } 28 | bool Color(void) const { return m_color; } 29 | bool Edge(void) const { return m_edge; } 30 | bool Sketch(void) const { return m_sketch; } 31 | bool Html(void) const { return m_html; } 32 | bool Tessellation(void) const { return m_tessellation; } 33 | double Quality(void) const { return m_quality; } 34 | int Batch(void) const { return m_batch; } 35 | bool SFA(void) const { return m_SFA; } 36 | bool GDT(void) const { return m_gdt; } 37 | bool Rosette(void) const { return m_rosette; } 38 | bool SectionCap(void) const { return m_cap; } 39 | bool TessSolid(void) const { return m_tessSolid; } 40 | 41 | // Software version (as of August 2024) 42 | const wstring Version(void) const { return L"1.50"; } 43 | 44 | private: 45 | wstring m_input; // Input file path 46 | wstring m_output; // Output file path 47 | bool m_normal; // Normal 48 | bool m_color; // Color 49 | bool m_edge; // Boundary edge 50 | bool m_sketch; // Sketch geometry 51 | bool m_html; // Output file type, html or x3d 52 | bool m_tessellation;// Tessellation type 53 | double m_quality; // Mesh quality 54 | int m_batch; // Batch option 55 | bool m_SFA; // Specific to SFA 56 | bool m_gdt; // GD&T option 57 | bool m_rosette; // Rosette used in Composite Design 58 | bool m_cap; // Section Cap 59 | bool m_tessSolid; // Tessellated Solid 60 | }; -------------------------------------------------------------------------------- /STP2X3D/STEP_Data.cpp: -------------------------------------------------------------------------------- 1 | #include "stdafx.h" 2 | #include "STEP_Data.h" 3 | 4 | 5 | 6 | STEP_Data::STEP_Data(const STEPControl_Reader& reader) 7 | :m_reader(reader) 8 | { 9 | StoreStepDataForShapes(); 10 | } 11 | 12 | STEP_Data::~STEP_Data(void) 13 | { 14 | Clear(); 15 | } 16 | 17 | void STEP_Data::StoreStepDataForShapes() 18 | { 19 | const Handle(XSControl_WorkSession)& workSession = m_reader.WS(); 20 | const Handle(Interface_InterfaceModel)& model = workSession->Model(); 21 | const Handle(XSControl_TransferReader)& transferReader = workSession->TransferReader(); 22 | const Handle(Transfer_TransientProcess)& transProcess = transferReader->TransientProcess(); 23 | 24 | int entitySize = model->NbEntities(); 25 | 26 | // Store STEP data for shapes 27 | for (int i = 1; i <= entitySize; ++i) 28 | { 29 | const Handle(Standard_Transient)& entity = model->Value(i); 30 | Handle(StepRepr_RepresentationItem) repItem = Handle(StepRepr_RepresentationItem)::DownCast(entity); 31 | 32 | // Skip if entity is not of type representation_item 33 | if (repItem.IsNull()) 34 | continue; 35 | 36 | const Handle(Transfer_Binder)& binder = transProcess->Find(entity); 37 | const TopoDS_Shape& shape = TransferBRep::ShapeResult(binder); 38 | 39 | // Skip if shape is null 40 | if (shape.IsNull()) 41 | continue; 42 | 43 | TopAbs_ShapeEnum shapeType = shape.ShapeType(); 44 | 45 | // Store compounds, compsolids, solids, and shells 46 | // Ignore lower-level elements such as faces 47 | if (shapeType == TopAbs_COMPOUND 48 | || shapeType == TopAbs_COMPSOLID 49 | || shapeType == TopAbs_SOLID 50 | || shapeType == TopAbs_SHELL) 51 | { 52 | int shapeID = OCCUtil::GetID(shape); 53 | 54 | // Entity type 55 | string stepEntityType = entity->DynamicType()->Name(); 56 | m_shapeIDentityTypeMap.insert({ shapeID,stepEntityType }); 57 | 58 | // Entity ID 59 | string id(workSession->EntityLabel(entity)->ToCString()); 60 | int stepEntityID = atoi(id.substr(1, id.length()).c_str()); 61 | m_shapeIDentityIDMap.insert({ shapeID,stepEntityID }); 62 | } 63 | } 64 | } 65 | 66 | const string STEP_Data::GetEntityTypeFromShape(const TopoDS_Shape& shape) const 67 | { 68 | int shapeID = OCCUtil::GetID(shape); 69 | string stepEntityType; 70 | 71 | if (m_shapeIDentityTypeMap.find(shapeID) != m_shapeIDentityTypeMap.end()) 72 | stepEntityType = m_shapeIDentityTypeMap.find(shapeID)->second; 73 | 74 | return stepEntityType; 75 | } 76 | 77 | const int STEP_Data::GetEntityIDFromShape(const TopoDS_Shape& shape) const 78 | { 79 | int shapeID = OCCUtil::GetID(shape); 80 | int stepEntityID = -1; 81 | 82 | if (m_shapeIDentityIDMap.find(shapeID) != m_shapeIDentityIDMap.end()) 83 | stepEntityID = m_shapeIDentityIDMap.find(shapeID)->second; 84 | 85 | return stepEntityID; 86 | } 87 | 88 | const string STEP_Data::GetEntityNameFromShape(const TopoDS_Shape& shape) const 89 | { 90 | int shapeID = OCCUtil::GetID(shape); 91 | string stepEntityName = ""; 92 | 93 | if (m_shapeIDentityNameMap.find(shapeID) != m_shapeIDentityNameMap.end()) 94 | stepEntityName = m_shapeIDentityNameMap.find(shapeID)->second; 95 | 96 | return stepEntityName; 97 | } 98 | 99 | bool STEP_Data::IsSolidModel(const TopoDS_Shape& shape) const 100 | { 101 | string type = GetEntityTypeFromShape(shape); 102 | 103 | if (type == "StepShape_ManifoldSolidBrep" // MANIFOLD_SOLID_BREP in STEP 104 | || type == "StepShape_BrepWithVoids" // BREP_WITH_VOIDS in STEP 105 | || type == "StepShape_FacetedBrep") // FACETED_BREP in STEP 106 | return true; 107 | 108 | return false; 109 | } 110 | 111 | bool STEP_Data::IsTessellatedSolidModel(const TopoDS_Shape& shape) const 112 | { 113 | string type = GetEntityTypeFromShape(shape); 114 | 115 | if (type == "StepVisual_TessellatedSolid") // TESSELLATED_SOLID in STEP 116 | return true; 117 | 118 | return false; 119 | } 120 | 121 | bool STEP_Data::IsSurfaceModel(const TopoDS_Shape& shape) const 122 | { 123 | string type = GetEntityTypeFromShape(shape); 124 | 125 | if (type == "StepShape_ShellBasedSurfaceModel" // SHELL_BASED_SURFACE_MODEL in STEP 126 | || type == "StepShape_GeometricSet") // GEOMETRIC_SET in STEP 127 | return true; 128 | 129 | return false; 130 | } 131 | 132 | bool STEP_Data::IsWireframeModel(const TopoDS_Shape& shape) const 133 | { 134 | string type = GetEntityTypeFromShape(shape); 135 | 136 | if (type == "StepShape_GeometricCurveSet" // GEOMETRIC_CURVE_SET in STEP 137 | || type == "StepShape_GeometricSet") // GEOMETRIC_SET in STEP 138 | return true; 139 | 140 | return false; 141 | } 142 | 143 | bool STEP_Data::IsShell(const TopoDS_Shape& shape) const 144 | { 145 | string type = GetEntityTypeFromShape(shape); 146 | 147 | if (type == "StepShape_ClosedShell" // CLOSED_SHELL in STEP 148 | || type == "StepShape_OrientedClosedShell" // ORIENTED_CLOSED_SHELL in STEP 149 | || type == "StepShape_OpenShell") // OPEN_SHELL in STEP 150 | return true; 151 | 152 | return false; 153 | } 154 | 155 | bool STEP_Data::IsMappedItem(const TopoDS_Shape& shape) const 156 | { 157 | string type = GetEntityTypeFromShape(shape); 158 | 159 | if (type == "StepRepr_MappedItem") // MAPPED_ITEM in STEP 160 | return true; 161 | 162 | return false; 163 | } 164 | 165 | void STEP_Data::AddRosetteGeometries(vector& rosettes) 166 | { 167 | const Handle(XSControl_WorkSession)& workSession = m_reader.WS(); 168 | const Handle(Interface_InterfaceModel)& model = workSession->Model(); 169 | const Handle(XSControl_TransferReader)& transferReader = workSession->TransferReader(); 170 | const Handle(Transfer_TransientProcess)& transProcess = transferReader->TransientProcess(); 171 | 172 | int entitySize = model->NbEntities(); 173 | 174 | // Store STEP data for shapes 175 | for (int i = 1; i <= entitySize; ++i) 176 | { 177 | const Handle(Standard_Transient)& entity = model->Value(i); 178 | string stepEntityType = entity->DynamicType()->Name(); 179 | 180 | if (stepEntityType == "StepData_UndefinedEntity") 181 | { 182 | Handle(StepData_UndefinedEntity) undefEnt = Handle(StepData_UndefinedEntity)::DownCast(entity); 183 | 184 | if (undefEnt->IsComplex()) 185 | { 186 | bool isCURVE_11 = false; // Rosette used in Composite Design 187 | 188 | while (undefEnt) 189 | { 190 | string type = undefEnt->StepType(); 191 | 192 | if (type == "CURVE_11") 193 | { 194 | isCURVE_11 = true; 195 | break; 196 | } 197 | 198 | undefEnt = undefEnt->Next(); 199 | } 200 | 201 | // Check CURVE_11 202 | if (isCURVE_11) 203 | undefEnt = Handle(StepData_UndefinedEntity)::DownCast(entity); 204 | else 205 | return; 206 | 207 | // Generate a composite_curve 208 | while (undefEnt) 209 | { 210 | string type = undefEnt->StepType(); 211 | 212 | if (type == "COMPOSITE_CURVE") 213 | { 214 | Handle(Interface_UndefinedContent) intUndefCont = undefEnt->UndefinedContent(); 215 | Interface_EntityList entList = intUndefCont->EntityList(); 216 | Handle(Standard_Transient) ent = entList.Value(1); 217 | 218 | Handle(StepData_UndefinedEntity) undefEnt2 = Handle(StepData_UndefinedEntity)::DownCast(ent); 219 | intUndefCont = undefEnt2->UndefinedContent(); 220 | 221 | entList = intUndefCont->EntityList(); 222 | 223 | int entCount = entList.NbEntities(); 224 | StepGeom_HArray1OfCompositeCurveSegment* compCurvSegArr = new StepGeom_HArray1OfCompositeCurveSegment(1, entCount); 225 | 226 | for (int i = 1; i <= entCount; ++i) 227 | { 228 | Handle(Standard_Transient) ent = entList.Value(i); 229 | Handle(StepGeom_CompositeCurveSegment) compCurvSeg = Handle(StepGeom_CompositeCurveSegment)::DownCast(ent); 230 | 231 | compCurvSegArr->SetValue(i, compCurvSeg); 232 | } 233 | 234 | Handle(StepGeom_HArray1OfCompositeCurveSegment) h_compCurvSegArr = Handle(StepGeom_HArray1OfCompositeCurveSegment)(compCurvSegArr); 235 | 236 | StepGeom_CompositeCurve* compCurv = new StepGeom_CompositeCurve(); 237 | compCurv->SetSegments(h_compCurvSegArr); 238 | Handle(StepGeom_CompositeCurve) h_compCurv = Handle(StepGeom_CompositeCurve)(compCurv); 239 | StepData_Factors* factors = new StepData_Factors(); 240 | StepToTopoDS_TranslateCompositeCurve* compCurvTrans = new StepToTopoDS_TranslateCompositeCurve(h_compCurv, transProcess, *factors); 241 | TopoDS_Shape shape = (TopoDS_Shape)compCurvTrans->Value(); 242 | 243 | if (!shape.IsNull()) 244 | { 245 | rosettes.push_back(shape); 246 | 247 | int shapeID = OCCUtil::GetID(shape); 248 | 249 | string id(workSession->EntityLabel(entity)->ToCString()); 250 | int stepEntityID = atoi(id.substr(1, id.length()).c_str()); 251 | m_shapeIDentityIDMap.insert({ shapeID,stepEntityID }); 252 | } 253 | 254 | break; 255 | } 256 | 257 | undefEnt = undefEnt->Next(); 258 | } 259 | } 260 | } 261 | } 262 | } 263 | 264 | void STEP_Data::AddSectionPlanes(vector& sectionPlanes) 265 | { 266 | const Handle(XSControl_WorkSession)& workSession = m_reader.WS(); 267 | const Handle(Interface_InterfaceModel)& model = workSession->Model(); 268 | 269 | int entitySize = model->NbEntities(); 270 | 271 | double factor = GetUnitConversionFactor(); // milli meter to inch if required 272 | 273 | for (int i = 1; i <= entitySize; ++i) 274 | { 275 | const Handle(Standard_Transient)& entity = model->Value(i); 276 | string stepEntityType = entity->DynamicType()->Name(); 277 | 278 | if (stepEntityType != "StepVisual_CameraModelD3MultiClipping") 279 | continue; 280 | 281 | Handle(StepVisual_CameraModelD3MultiClipping) cameraModel = Handle(StepVisual_CameraModelD3MultiClipping)::DownCast(entity); 282 | Handle(StepVisual_HArray1OfCameraModelD3MultiClippingInterectionSelect) clippingArr = cameraModel->ShapeClipping(); 283 | 284 | if (clippingArr->Length() > 1) 285 | continue; 286 | 287 | Handle(StepGeom_Plane) clippingPlane = Handle(StepGeom_Plane)::DownCast(clippingArr->First().Value()); 288 | 289 | if (!clippingPlane) 290 | continue; 291 | 292 | Handle(StepGeom_Axis2Placement3d) axis2Placement3d = clippingPlane->Position(); 293 | Handle(StepGeom_CartesianPoint) point = axis2Placement3d->Location(); 294 | Handle(StepGeom_Direction) axis = axis2Placement3d->Axis(); 295 | Handle(StepGeom_Direction) refDir = axis2Placement3d->RefDirection(); 296 | 297 | double p1 = factor * point->CoordinatesValue(1); 298 | double p2 = factor * point->CoordinatesValue(2); 299 | double p3 = factor * point->CoordinatesValue(3); 300 | 301 | double z1 = axis->DirectionRatiosValue(1); 302 | double z2 = axis->DirectionRatiosValue(2); 303 | double z3 = axis->DirectionRatiosValue(3); 304 | 305 | double x1, x2, x3; 306 | gp_Pln* plane = nullptr; 307 | 308 | if (refDir) 309 | { 310 | x1 = refDir->DirectionRatiosValue(1); 311 | x2 = refDir->DirectionRatiosValue(2); 312 | x3 = refDir->DirectionRatiosValue(3); 313 | 314 | if (gp_Dir(x1, x2, x3).IsOpposite(gp_Dir(z1, z2, z3), Precision::Confusion()) 315 | || gp_Dir(x1, x2, x3).IsEqual(gp_Dir(z1, z2, z3), Precision::Confusion())) 316 | { 317 | // Wrong ref direction 318 | //plane = new gp_Pln(gp_Pnt(p1, p2, p3), gp_Dir(z1, z2, z3)); 319 | continue; 320 | } 321 | else 322 | { 323 | plane = new gp_Pln(gp_Ax3(gp_Pnt(p1, p2, p3), gp_Dir(z1, z2, z3), gp_Dir(x1, x2, x3))); 324 | } 325 | } 326 | else 327 | { 328 | plane = new gp_Pln(gp_Pnt(p1, p2, p3), gp_Dir(z1, z2, z3)); 329 | } 330 | 331 | BRepBuilderAPI_MakeFace face(*plane); 332 | TopoDS_Shape planeShape = face.Shape(); 333 | 334 | if (planeShape.IsNull()) 335 | continue; 336 | 337 | sectionPlanes.push_back(planeShape); 338 | 339 | int shapeID = OCCUtil::GetID(planeShape); 340 | string name = cameraModel->Name()->ToCString(); 341 | 342 | string id(workSession->EntityLabel(entity)->ToCString()); 343 | int stepEntityID = atoi(id.substr(1, id.length()).c_str()); 344 | m_shapeIDentityIDMap.insert({ shapeID,stepEntityID }); 345 | m_shapeIDentityNameMap.insert({ shapeID,name }); 346 | } 347 | } 348 | 349 | double STEP_Data::GetUnitConversionFactor(void) 350 | { 351 | double factor = 1.0; 352 | 353 | const Handle(XSControl_WorkSession)& workSession = m_reader.WS(); 354 | const Handle(Interface_InterfaceModel)& model = workSession->Model(); 355 | 356 | int entitySize = model->NbEntities(); 357 | 358 | for (int i = 1; i <= entitySize; ++i) 359 | { 360 | const Handle(Standard_Transient)& entity = model->Value(i); 361 | string stepEntityType = entity->DynamicType()->Name(); 362 | 363 | if (stepEntityType != "StepShape_AdvancedBrepShapeRepresentation") 364 | continue; 365 | 366 | Handle(StepShape_AdvancedBrepShapeRepresentation) adv = Handle(StepShape_AdvancedBrepShapeRepresentation)::DownCast(entity); 367 | int num = workSession->Model()->Number(adv->ContextOfItems()); 368 | const Handle(Standard_Transient)& ent = workSession->Model()->Value(num); 369 | 370 | Handle(StepGeom_GeomRepContextAndGlobUnitAssCtxAndGlobUncertaintyAssCtx) contexts = Handle(StepGeom_GeomRepContextAndGlobUnitAssCtxAndGlobUncertaintyAssCtx)::DownCast(ent); 371 | Handle(StepRepr_GlobalUnitAssignedContext) unitContext = contexts->GlobalUnitAssignedContext(); 372 | Handle(StepBasic_HArray1OfNamedUnit) units = unitContext->Units(); 373 | 374 | int len = units->Length(); 375 | 376 | for (int j = 1; j <= len; ++j) 377 | { 378 | Handle(StepBasic_ConversionBasedUnit) convUnit = Handle(StepBasic_ConversionBasedUnit)::DownCast(units->Value(j)); 379 | 380 | if (!convUnit) 381 | continue; 382 | 383 | string name = StrTool::ToLower(convUnit->Name()->ToCString()); 384 | 385 | if (name != "inch") 386 | continue; 387 | 388 | Handle(StepBasic_MeasureWithUnit) mwu = convUnit->ConversionFactor(); 389 | Handle(StepBasic_MeasureValueMember) mvm = mwu->ValueComponentMember(); 390 | 391 | string type = mvm->Name(); 392 | 393 | if (type != "LENGTH_MEASURE") 394 | break; 395 | 396 | factor = mwu->ValueComponent(); 397 | break; 398 | } 399 | 400 | if (factor != 1.0) 401 | break; 402 | 403 | /* 404 | if (stepEntityType == "StepGeom_GeomRepContextAndGlobUnitAssCtxAndGlobUncertaintyAssCtx") 405 | { 406 | Handle(StepGeom_GeomRepContextAndGlobUnitAssCtxAndGlobUncertaintyAssCtx) context = Handle(StepGeom_GeomRepContextAndGlobUnitAssCtxAndGlobUncertaintyAssCtx)::DownCast(entity); 407 | Handle(StepRepr_GlobalUnitAssignedContext) unitContext = context->GlobalUnitAssignedContext(); 408 | 409 | Handle(StepBasic_HArray1OfNamedUnit) units = unitContext->Units(); 410 | int len = units->Length(); 411 | 412 | for (int j = 1; j <= len; ++j) 413 | { 414 | Handle(StepBasic_ConversionBasedUnit) unit = Handle(StepBasic_ConversionBasedUnit)::DownCast(units->Value(j)); 415 | 416 | if (unit) 417 | { 418 | Handle(StepBasic_MeasureWithUnit) mwu = unit->ConversionFactor(); 419 | Handle(StepBasic_MeasureValueMember) member = mwu->ValueComponentMember(); 420 | 421 | string type = member->Name(); 422 | 423 | if (type == "LENGTH_MEASURE") 424 | { 425 | factor = mwu->ValueComponent(); 426 | break; 427 | } 428 | } 429 | } 430 | 431 | if (factor != 1.0) 432 | break; 433 | } 434 | */ 435 | } 436 | 437 | return factor; 438 | } 439 | 440 | void STEP_Data::Clear(void) 441 | { 442 | m_shapeIDentityTypeMap.clear(); 443 | m_shapeIDentityIDMap.clear(); 444 | } -------------------------------------------------------------------------------- /STP2X3D/STEP_Data.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | 4 | class STEP_Data 5 | { 6 | public: 7 | STEP_Data(const STEPControl_Reader& reader); 8 | ~STEP_Data(void); 9 | 10 | const string GetEntityTypeFromShape(const TopoDS_Shape& shape) const; 11 | const int GetEntityIDFromShape(const TopoDS_Shape& shape) const; 12 | const string GetEntityNameFromShape(const TopoDS_Shape& shape) const; 13 | 14 | bool IsSolidModel(const TopoDS_Shape& shape) const; 15 | bool IsTessellatedSolidModel(const TopoDS_Shape& shape) const; 16 | bool IsSurfaceModel(const TopoDS_Shape& shape) const; 17 | bool IsWireframeModel(const TopoDS_Shape& shape) const; 18 | bool IsShell(const TopoDS_Shape& shape) const; 19 | 20 | bool IsMappedItem(const TopoDS_Shape& shape) const; 21 | 22 | void AddRosetteGeometries(vector& rosettes); 23 | void AddSectionPlanes(vector& sectionPlanes); 24 | 25 | protected: 26 | void StoreStepDataForShapes(void); 27 | double GetUnitConversionFactor(void); 28 | void Clear(void); 29 | 30 | private: 31 | unordered_map m_shapeIDentityTypeMap; 32 | unordered_map m_shapeIDentityIDMap; 33 | unordered_map m_shapeIDentityNameMap; 34 | 35 | STEPControl_Reader m_reader; 36 | }; -------------------------------------------------------------------------------- /STP2X3D/STEP_Reader.cpp: -------------------------------------------------------------------------------- 1 | #include "stdafx.h" 2 | #include "STEP_Reader.h" 3 | #include "STEP_Data.h" 4 | #include "Component.h" 5 | #include "IShape.h" 6 | #include "GDT_Item.h" 7 | 8 | STEP_Reader::STEP_Reader(S2X_Option* opt) 9 | : m_opt(opt), 10 | m_stepData(nullptr) 11 | { 12 | m_defaultFaceColor.SetValues(0.55f, 0.55f, 0.6f, 1.0f); // Grey 13 | m_defaultWireColor.SetValues(1.0f, 1.0f, 1.0f, 1.0f); // White 14 | } 15 | 16 | STEP_Reader::~STEP_Reader(void) 17 | { 18 | Clear(); 19 | } 20 | 21 | bool STEP_Reader::ReadSTEP(Model* model) 22 | { 23 | IFSelect_ReturnStatus status; 24 | wstring filePath = m_opt->Input(); 25 | OSD::SetSignal(false); 26 | 27 | try 28 | { 29 | // Read a STEP file 30 | STEPCAFControl_Reader cafReader; 31 | cafReader.SetNameMode(true); 32 | 33 | if (m_opt->Color()) 34 | cafReader.SetColorMode(true); 35 | 36 | if (m_opt->GDT()) 37 | cafReader.SetGDTMode(true); 38 | 39 | TCollection_AsciiString aFileName((const wchar_t*)filePath.c_str()); 40 | status = cafReader.ReadFile(aFileName.ToCString()); 41 | //cafReader.Reader().PrintCheckLoad(false, (IFSelect_PrintCount)0); 42 | 43 | if (!CheckReturnStatus(status)) 44 | return false; 45 | 46 | Handle(TDocStd_Document) doc = new TDocStd_Document("MDTV-XCAF"); 47 | 48 | if (cafReader.Transfer(doc)) 49 | { 50 | m_stepData = new STEP_Data(cafReader.Reader()); 51 | m_shapeTool = XCAFDoc_DocumentTool::ShapeTool(doc->Main()); 52 | m_colorTool = XCAFDoc_DocumentTool::ColorTool(doc->Main()); 53 | m_gdtTool = XCAFDoc_DocumentTool::DimTolTool(doc->Main()); 54 | m_viewTool = XCAFDoc_DocumentTool::ViewTool(doc->Main()); 55 | //m_noteTool = XCAFDoc_DocumentTool::NotesTool(doc->Main()); 56 | 57 | // Read GD&T information 58 | if (m_opt->GDT()) 59 | ReadGDT(model); 60 | 61 | // Update color option if there's no color 62 | UpdateColorOption(); 63 | 64 | // Get free shapes 65 | TDF_LabelSequence labels_shapes; 66 | m_shapeTool->GetFreeShapes(labels_shapes); 67 | 68 | // It's usually 1 for assemblies 69 | int shapeSize = labels_shapes.Length(); 70 | 71 | // Save shapes, structure, and colors to the model 72 | for (int i = 1; i <= shapeSize; ++i) 73 | { 74 | const TDF_Label& label_shape = labels_shapes.Value(i); 75 | TopoDS_Shape& shape = m_shapeTool->GetShape(label_shape); 76 | 77 | Component* rootComp = new Component(shape); 78 | rootComp->SetUniqueName(GetName(label_shape)); 79 | model->AddRootComponent(rootComp); 80 | 81 | AddSubComponents(rootComp, label_shape); 82 | 83 | if (i == 1) 84 | { 85 | AddRosettes(rootComp); 86 | AddSectionCaps(rootComp); 87 | } 88 | } 89 | } 90 | } 91 | catch (Standard_Failure& e) 92 | { 93 | model->Clear(); 94 | UpdateColorOption(); 95 | 96 | const char* errMsg = e.GetMessageString(); 97 | cout << "\tStandard_Failure(" << errMsg << ") occured." << endl; 98 | cout << "\tColor will not be supported." << endl; 99 | 100 | // Read a STEP file 101 | STEPControl_Reader reader; 102 | TCollection_AsciiString aFileName((const wchar_t*)filePath.c_str()); 103 | status = reader.ReadFile(aFileName.ToCString()); 104 | //status = reader.ReadFile(filePath.c_str()); 105 | 106 | if (!CheckReturnStatus(status)) 107 | return false; 108 | 109 | if (reader.TransferRoot()) 110 | { 111 | //m_stepData = new STEP_Data(reader); 112 | 113 | const TopoDS_Shape& shape = reader.Shape(); 114 | IShape* iShape = new IShape(shape); 115 | 116 | Component* rootComp = new Component(shape); 117 | rootComp->AddIShape(iShape); 118 | model->AddRootComponent(rootComp); 119 | } 120 | } 121 | catch (...) 122 | { 123 | // Unknown failure 124 | return CheckReturnStatus(IFSelect_RetFail); 125 | } 126 | 127 | model->Update(); 128 | 129 | // Terminate if the root comp is empty 130 | if (model->IsEmpty()) 131 | return CheckReturnStatus(IFSelect_RetVoid); 132 | 133 | return true; 134 | } 135 | 136 | void STEP_Reader::AddSubComponents(Component*& comp, const TDF_Label& label) 137 | { 138 | // Check label type 139 | if (m_shapeTool->IsAssembly(label)) // Assembly or sub-assembly component 140 | { 141 | comp->SetUniqueName(GetName(label)); // Set the component's name 142 | 143 | TDF_LabelSequence label_comps; 144 | m_shapeTool->GetComponents(label, label_comps); 145 | 146 | int compSize = label_comps.Length(); 147 | 148 | for (int i = 1; i <= compSize; ++i) 149 | { 150 | const TDF_Label& label_comp = label_comps.Value(i); 151 | AddSubComponents(comp, label_comp); // Recursive call 152 | } 153 | } 154 | else if (m_shapeTool->IsReference(label)) // Reference (Part or Asssembly) 155 | { 156 | TDF_Label label_ref; 157 | m_shapeTool->GetReferredShape(label, label_ref); 158 | 159 | const TopoDS_Shape& refShape = m_shapeTool->GetShape(label_ref); 160 | const gp_Trsf& trsf = m_shapeTool->GetLocation(label).Transformation(); 161 | 162 | if (IsEmpty(refShape)) 163 | return; 164 | 165 | Component* subComp = new Component(refShape); // New subcomp 166 | subComp->SetUniqueName(GetName(label_ref)); // Set the name 167 | subComp->SetTransformation(trsf); // Set the transformation 168 | 169 | if (m_stepData->GetEntityTypeFromShape(refShape) == "StepShape_ManifoldSolidBrep") 170 | subComp->SetStepID(m_stepData->GetEntityIDFromShape(refShape)); // STEP Entity ID 171 | 172 | comp->AddSubComponent(subComp); // Add the subcomp (This should be here!) 173 | 174 | // Skip if the subcomp is a copy 175 | if (IsCopy(subComp)) 176 | return; 177 | 178 | AddSubComponents(subComp, label_ref); // Recursive call 179 | } 180 | else if (m_shapeTool->IsSimpleShape(label)) // Part component or just shape 181 | { 182 | const TopoDS_Shape& shape = m_shapeTool->GetShape(label); 183 | 184 | if (!m_opt->TessSolid() 185 | && m_stepData->IsTessellatedSolidModel(shape)) 186 | return; 187 | 188 | if (IsEmpty(shape)) 189 | return; 190 | 191 | vector subShapes; 192 | GetSubShapes(shape, subShapes); 193 | 194 | // Add each sub shape 195 | for (const auto& subShape : subShapes) 196 | { 197 | IShape* iShape = new IShape(subShape); 198 | iShape->SetStepID(m_stepData->GetEntityIDFromShape(subShape)); // STEP Entity ID 199 | 200 | if (m_stepData->IsTessellatedSolidModel(shape)) 201 | iShape->SetTessSolidModel(true); 202 | 203 | comp->AddIShape(iShape); 204 | 205 | AddColors(iShape); // Add colors for each face OR edge 206 | } 207 | 208 | subShapes.clear(); 209 | } 210 | } 211 | 212 | void STEP_Reader::GetSubShapes(const TopoDS_Shape& shape, vector& subShapes) const 213 | { 214 | TopAbs_ShapeEnum shapeType = shape.ShapeType(); 215 | 216 | if (shapeType == TopAbs_COMPOUND) 217 | { 218 | // Free wires or edges 219 | if (OCCUtil::IsFreeEdge(shape)) 220 | { 221 | if (m_opt->Sketch()) 222 | subShapes.push_back(shape); 223 | 224 | return; 225 | } 226 | 227 | // Solid or suface models in STEP 228 | if (m_stepData->IsSolidModel(shape) 229 | || m_stepData->IsSurfaceModel(shape)) 230 | { 231 | subShapes.push_back(shape); 232 | return; 233 | } 234 | 235 | // Mapped_item in STEP (Need to check) 236 | if (m_stepData->IsMappedItem(shape)) 237 | return; 238 | 239 | // Traverse the compound shape 240 | for (TopoDS_Iterator exp(shape); exp.More(); exp.Next()) 241 | { 242 | const TopoDS_Shape& subShape = exp.Value(); 243 | GetSubShapes(subShape, subShapes); // Recursive call 244 | } 245 | } 246 | else if (shapeType == TopAbs_COMPSOLID 247 | || shapeType == TopAbs_SOLID 248 | || shapeType == TopAbs_SHELL) 249 | { 250 | subShapes.push_back(shape); 251 | return; 252 | } 253 | } 254 | 255 | const wstring STEP_Reader::GetName(const TDF_Label& label) const 256 | { 257 | Handle(TDataStd_Name) nameData; 258 | TCollection_ExtendedString nameText; 259 | 260 | if (label.FindAttribute(TDataStd_Name::GetID(), nameData)) 261 | nameText = nameData->Get(); 262 | 263 | /* 264 | stringstream ss; 265 | ss << nameText << endl; 266 | 267 | string s = ss.str(); 268 | wstring name = StrTool::s2ws(s); //nameText.ToWideString(); 269 | */ 270 | 271 | // Convert UTF-16 string(char16_t) to UTF-8 string(wstring) 272 | wstring name = StrTool::u16str2wstr(nameText.ToExtString()); 273 | 274 | // Remove extra linefeed 275 | name = StrTool::RemoveCharacter(name, L"\r"); 276 | name = StrTool::RemoveCharacter(name, L"\n"); 277 | 278 | // Ignore the names below 279 | if (name == L"COMPOUND" 280 | || name == L"COMPSOLID" 281 | || name == L"SOLID" 282 | || name == L"SHELL" 283 | || (name.find(L"=>[") == 0 284 | && name.find(L"]") == name.length() - 1)) 285 | name.clear(); 286 | 287 | return name; 288 | } 289 | 290 | bool STEP_Reader::IsCopy(Component*& comp) 291 | { 292 | const TopoDS_Shape& shape = comp->GetShape(); 293 | int shapeID = OCCUtil::GetID(shape); 294 | 295 | // Check if there's a component with the same id in the map 296 | if (m_idComponentMap.find(shapeID) == m_idComponentMap.end()) 297 | m_idComponentMap.insert({ shapeID,comp }); 298 | else 299 | { 300 | Component* originalComp = m_idComponentMap[shapeID]; 301 | comp->SetOriginalComponent(originalComp); 302 | 303 | return true; 304 | } 305 | 306 | return false; 307 | } 308 | 309 | bool STEP_Reader::IsEmpty(const TopoDS_Shape& shape) const 310 | { 311 | if (!shape.IsNull() 312 | || OCCUtil::HasFace(shape) 313 | || OCCUtil::HasEdge(shape)) 314 | return false; 315 | 316 | return true; 317 | 318 | //if (shape.IsNull() 319 | // || (m_opt->Sketch() && !OCCUtil::HasEdge(shape)) // If sketch is on, check edges 320 | // || (!m_opt->Sketch() && !OCCUtil::HasFace(shape))) // If sketch is off, check faces 321 | // return true; 322 | 323 | //return false; 324 | } 325 | 326 | void STEP_Reader::AddColors(IShape*& iShape) const 327 | { 328 | if (!m_opt->Color()) 329 | return; 330 | 331 | const TopoDS_Shape& shape = iShape->GetShape(); 332 | 333 | // OCCT 7.4.0 doesn't read transparency from STEP AP242 files 334 | if (iShape->IsFaceSet()) // Face set (Solids, Shells) 335 | { 336 | // Get solid or shell color 337 | Quantity_ColorRGBA solidColor; 338 | bool isSolidColored = false; 339 | 340 | if (m_colorTool->GetColor(shape, XCAFDoc_ColorSurf, solidColor)) 341 | isSolidColored = true; 342 | 343 | TopExp_Explorer ExpFace; 344 | for (ExpFace.Init(shape, TopAbs_FACE); ExpFace.More(); ExpFace.Next()) 345 | { 346 | const TopoDS_Shape& face = ExpFace.Current(); 347 | 348 | // Get face color 349 | Quantity_ColorRGBA faceColor; 350 | bool isFaceColored = false; 351 | 352 | if (m_colorTool->GetColor(face, XCAFDoc_ColorSurf, faceColor)) 353 | isFaceColored = true; 354 | 355 | // Priority: face color -> solid color -> default color 356 | if (isFaceColored) 357 | iShape->AddColor(face, faceColor); 358 | else if (isSolidColored) 359 | iShape->AddColor(face, solidColor); 360 | else 361 | iShape->AddColor(face, m_defaultFaceColor); 362 | } 363 | } 364 | else // Wire set (Wires, Edges) 365 | { 366 | // Free wires 367 | TopExp_Explorer ExpWire; 368 | for (ExpWire.Init(shape, TopAbs_WIRE); ExpWire.More(); ExpWire.Next()) 369 | { 370 | const TopoDS_Shape& wire = ExpWire.Current(); 371 | 372 | // Get wire color 373 | Quantity_ColorRGBA wireColor; 374 | bool isWireColored = false; 375 | 376 | if (m_colorTool->GetColor(wire, XCAFDoc_ColorCurv, wireColor)) 377 | isWireColored = true; 378 | 379 | TopExp_Explorer ExpEdge; 380 | for (ExpEdge.Init(wire, TopAbs_EDGE); ExpEdge.More(); ExpEdge.Next()) 381 | { 382 | const TopoDS_Shape& edge = ExpEdge.Current(); 383 | 384 | // Get edge color 385 | Quantity_ColorRGBA edgeColor; 386 | bool isEdgeColored = false; 387 | 388 | if (m_colorTool->GetColor(edge, XCAFDoc_ColorCurv, edgeColor)) 389 | isEdgeColored = true; 390 | 391 | // Priority: edge color -> wire color -> default color 392 | if (isEdgeColored) 393 | iShape->AddColor(edge, edgeColor); 394 | else if (isWireColored) 395 | iShape->AddColor(edge, wireColor); 396 | else 397 | iShape->AddColor(edge, m_defaultWireColor); 398 | } 399 | } 400 | 401 | // Free edges 402 | TopExp_Explorer ExpEdge; 403 | for (ExpEdge.Init(shape, TopAbs_EDGE, TopAbs_WIRE); ExpEdge.More(); ExpEdge.Next()) 404 | { 405 | const TopoDS_Shape& edge = ExpEdge.Current(); 406 | 407 | // Get edge color 408 | Quantity_ColorRGBA edgeColor; 409 | bool isEdgeColored = false; 410 | 411 | if (m_colorTool->GetColor(edge, XCAFDoc_ColorCurv, edgeColor)) 412 | isEdgeColored = true; 413 | 414 | // Priority: edge color -> default color 415 | if (isEdgeColored) 416 | iShape->AddColor(edge, edgeColor); 417 | else 418 | iShape->AddColor(edge, m_defaultWireColor); 419 | } 420 | } 421 | } 422 | 423 | bool STEP_Reader::CheckReturnStatus(const IFSelect_ReturnStatus& status) const 424 | { 425 | bool isDone = false; 426 | 427 | if (status == IFSelect_RetDone) 428 | isDone = true; 429 | else 430 | { 431 | switch (status) 432 | { 433 | case IFSelect_RetError: 434 | printf("Not a valid STEP file.\n"); 435 | break; 436 | case IFSelect_RetFail: 437 | printf("Reading has failed.\n"); 438 | break; 439 | case IFSelect_RetVoid: 440 | printf("Nothing to translate.\n"); 441 | break; 442 | case IFSelect_RetStop: 443 | printf("Reading has stopped.\n"); 444 | break; 445 | } 446 | } 447 | 448 | return isDone; 449 | } 450 | 451 | void STEP_Reader::UpdateColorOption() const 452 | { 453 | if (!m_opt->Color()) 454 | return; 455 | 456 | if (!m_colorTool) // If the default STEP reader has failed 457 | m_opt->SetColor(0); 458 | else 459 | { 460 | TDF_LabelSequence colorLabels; 461 | m_colorTool->GetColors(colorLabels); 462 | 463 | // Check the number of colors defined in the model 464 | int colorSize = colorLabels.Length(); 465 | 466 | if (colorSize == 0) 467 | m_opt->SetColor(0); 468 | } 469 | } 470 | 471 | void STEP_Reader::Clear(void) 472 | { 473 | m_idComponentMap.clear(); 474 | delete m_stepData; 475 | } 476 | 477 | // Read geometries related to GD&T with semantic and graphical PMI (Work in progress) 478 | void STEP_Reader::ReadGDT(Model*& model) const 479 | { 480 | TDF_LabelSequence labels_datums, label_geoms, label_dims, label_dimTols; 481 | m_gdtTool->GetDatumLabels(labels_datums); 482 | m_gdtTool->GetDimensionLabels(label_dims); 483 | m_gdtTool->GetGeomToleranceLabels(label_geoms); 484 | 485 | int datumSize = labels_datums.Length(); 486 | int dimSize = label_dims.Length(); 487 | int geomSize = label_geoms.Length(); 488 | 489 | // Geometric Tolerances 490 | for (int i = 1; i <= geomSize; ++i) 491 | { 492 | const TDF_Label& label_geom = label_geoms.Value(i); 493 | 494 | Handle(XCAFDoc_GeomTolerance) aGeomAttr; 495 | label_geom.FindAttribute(XCAFDoc_GeomTolerance::GetID(), aGeomAttr); 496 | 497 | if (!aGeomAttr.IsNull()) 498 | { 499 | Handle(XCAFDimTolObjects_GeomToleranceObject) aGeomObject = aGeomAttr->GetObject(); 500 | Handle(TCollection_HAsciiString) name = aGeomObject->GetPresentationName(); 501 | 502 | if (!name) 503 | name = aGeomObject->GetSemanticName(); 504 | 505 | XCAFDimTolObjects_GeomToleranceType type = aGeomObject->GetType(); 506 | XCAFDimTolObjects_GeomToleranceTypeValue typeVal = aGeomObject->GetTypeOfValue(); 507 | double val = aGeomObject->GetValue(); 508 | 509 | double maxValModVal = aGeomObject->GetMaxValueModifier(); 510 | 511 | XCAFDimTolObjects_GeomToleranceZoneModif zoneModif = aGeomObject->GetZoneModifier(); 512 | double zoneModVal = aGeomObject->GetValueOfZoneModifier(); 513 | 514 | //Handle(TCollection_HAsciiString) ascHSemNameStr = aGeomObject->GetSemanticName(); 515 | //TCollection_AsciiString ascSemNameStr = ascHSemNameStr->String(); 516 | 517 | //TDF_LabelSequence datums; 518 | //m_gdtTool->GetDatumOfTolerLabels(label_geom, datums); 519 | 520 | if (name) 521 | { 522 | TCollection_AsciiString ascNameStr = name->String(); 523 | wstring nameStr = StrTool::str2wstr(ascNameStr.ToCString()); 524 | 525 | // Get shape 526 | TDF_LabelSequence fir, sec; 527 | m_gdtTool->GetRefShapeLabel(label_geom, fir, sec); 528 | 529 | GDT_Item* gdt = nullptr; 530 | if (!(gdt = model->GetGDTByName(nameStr))) 531 | { 532 | gdt = new GDT_Item(nameStr); 533 | model->AddGDT(gdt); 534 | } 535 | 536 | for (int j = 1; j <= fir.Length(); ++j) 537 | { 538 | const TDF_Label& label_shape = fir.Value(1); 539 | const TopoDS_Shape& shape = m_shapeTool->GetShape(label_shape); 540 | 541 | gdt->AddShape(shape); 542 | } 543 | 544 | for (int j = 1; j <= sec.Length(); ++j) 545 | { 546 | const TDF_Label& label_shape = sec.Value(1); 547 | const TopoDS_Shape& shape = m_shapeTool->GetShape(label_shape); 548 | 549 | gdt->AddShape(shape); 550 | } 551 | 552 | const TopoDS_Shape& pptShape = aGeomObject->GetPresentation(); 553 | 554 | if (!pptShape.IsNull()) 555 | gdt->AddShape(pptShape); 556 | } 557 | } 558 | } 559 | 560 | // Dimensional Tolerances 561 | for (int i = 1; i <= dimSize; ++i) 562 | { 563 | const TDF_Label& label_dim = label_dims.Value(i); 564 | 565 | Handle(XCAFDoc_Dimension) aDimAttr; 566 | label_dim.FindAttribute(XCAFDoc_Dimension::GetID(), aDimAttr); 567 | 568 | if (!aDimAttr.IsNull()) 569 | { 570 | Handle(XCAFDimTolObjects_DimensionObject) aDimObject = aDimAttr->GetObject(); 571 | Handle(TCollection_HAsciiString) name = aDimObject->GetPresentationName(); 572 | 573 | if (!name) 574 | name = aDimObject->GetSemanticName(); 575 | 576 | double val = aDimObject->GetValue(); 577 | double lowerTolVal = aDimObject->GetLowerTolValue(); 578 | double lowerBoundVal = aDimObject->GetLowerBound(); 579 | double upperTolVal = aDimObject->GetUpperTolValue(); 580 | double upperBound = aDimObject->GetUpperBound(); 581 | XCAFDimTolObjects_DimensionType dimType = aDimObject->GetType(); 582 | XCAFDimTolObjects_DimensionQualifier dimQualifier = aDimObject->GetQualifier(); 583 | 584 | Handle(TColStd_HArray1OfReal) vals = aDimObject->GetValues(); 585 | //int valSize = vals->Size(); 586 | 587 | //Handle(TCollection_HAsciiString) ascHSemNameStr = aDimObject->GetSemanticName(); 588 | //TCollection_AsciiString ascSemNameStr = ascHSemNameStr->String(); 589 | 590 | if (name) 591 | { 592 | TCollection_AsciiString ascNameStr = name->String(); 593 | wstring nameStr = StrTool::str2wstr(ascNameStr.ToCString()); 594 | 595 | // Get shape 596 | TDF_LabelSequence fir, sec; 597 | m_gdtTool->GetRefShapeLabel(label_dim, fir, sec); 598 | 599 | GDT_Item* gdt = nullptr; 600 | if (!(gdt = model->GetGDTByName(nameStr))) 601 | { 602 | gdt = new GDT_Item(nameStr); 603 | model->AddGDT(gdt); 604 | } 605 | 606 | for (int j = 1; j <= fir.Length(); ++j) 607 | { 608 | const TDF_Label& label_shape = fir.Value(1); 609 | const TopoDS_Shape& shape = m_shapeTool->GetShape(label_shape); 610 | 611 | gdt->AddShape(shape); 612 | } 613 | 614 | for (int j = 1; j <= sec.Length(); ++j) 615 | { 616 | const TDF_Label& label_shape = sec.Value(1); 617 | const TopoDS_Shape& shape = m_shapeTool->GetShape(label_shape); 618 | 619 | gdt->AddShape(shape); 620 | } 621 | 622 | const TopoDS_Shape& pptShape = aDimObject->GetPresentation(); 623 | 624 | if (!pptShape.IsNull()) 625 | gdt->AddShape(pptShape); 626 | } 627 | } 628 | } 629 | 630 | // Datums 631 | for (int i = 1; i <= datumSize; ++i) 632 | { 633 | const TDF_Label& label_datum = labels_datums.Value(i); 634 | 635 | TDF_LabelSequence labels_views; 636 | m_viewTool->GetViewLabelsForGDT(label_datum, labels_views); 637 | int viewSize = labels_views.Length(); 638 | 639 | Handle(XCAFDoc_Datum) aDatumAttr; 640 | label_datum.FindAttribute(XCAFDoc_Datum::GetID(), aDatumAttr); 641 | 642 | if (!aDatumAttr.IsNull()) 643 | { 644 | Handle(XCAFDimTolObjects_DatumObject) aDatumObject = aDatumAttr->GetObject(); 645 | Handle(TCollection_HAsciiString) name = aDatumObject->GetPresentationName(); 646 | 647 | if (!name) 648 | name = aDatumObject->GetSemanticName(); 649 | 650 | const TopoDS_Shape& targetShape = aDatumObject->GetDatumTarget(); 651 | double targetLength = aDatumObject->GetDatumTargetLength(); 652 | double targetWidth = aDatumObject->GetDatumTargetWidth(); 653 | 654 | int targetNum = aDatumObject->GetDatumTargetNumber(); 655 | 656 | XCAFDimTolObjects_DatumTargetType targetType = aDatumObject->GetDatumTargetType(); 657 | gp_Ax2 axis = aDatumObject->GetDatumTargetAxis(); 658 | 659 | //TDF_LabelSequence geomTols; 660 | //m_gdtTool->GetTolerOfDatumLabels(label_datum, geomTols); 661 | 662 | //Handle(TCollection_HAsciiString) ascHSemNameStr = aDatumObject->GetSemanticName(); 663 | //TCollection_AsciiString ascSemNameStr = ascHSemNameStr->String(); 664 | 665 | if (name) 666 | { 667 | TCollection_AsciiString ascNameStr = name->String(); 668 | wstring nameStr = StrTool::str2wstr(ascNameStr.ToCString()); 669 | 670 | // Get shape 671 | TDF_LabelSequence fir, sec; 672 | m_gdtTool->GetRefShapeLabel(label_datum, fir, sec); 673 | 674 | GDT_Item* gdt = nullptr; 675 | if (!(gdt = model->GetGDTByName(nameStr))) 676 | { 677 | gdt = new GDT_Item(nameStr); 678 | model->AddGDT(gdt); 679 | } 680 | 681 | for (int j = 1; j <= fir.Length(); ++j) 682 | { 683 | const TDF_Label& label_shape = fir.Value(1); 684 | const TopoDS_Shape& shape = m_shapeTool->GetShape(label_shape); 685 | 686 | gdt->AddShape(shape); 687 | } 688 | 689 | for (int j = 1; j <= sec.Length(); ++j) 690 | { 691 | const TDF_Label& label_shape = sec.Value(1); 692 | const TopoDS_Shape& shape = m_shapeTool->GetShape(label_shape); 693 | 694 | gdt->AddShape(shape); 695 | } 696 | 697 | const TopoDS_Shape& pptShape = aDatumObject->GetPresentation(); 698 | if (!pptShape.IsNull()) 699 | gdt->AddShape(pptShape); 700 | } 701 | } 702 | } 703 | 704 | // Disable GDT option when no GDT item exists 705 | if (geomSize == 0 706 | && datumSize == 0 707 | && dimSize == 0) 708 | m_opt->SetGDT(false); 709 | } 710 | 711 | void STEP_Reader::AddRosettes(Component*& rootComp) 712 | { 713 | if (!m_opt->Rosette()) 714 | return; 715 | 716 | vector rosettes; 717 | m_stepData->AddRosetteGeometries(rosettes); 718 | 719 | TopoDS_Shape rootShape = rootComp->GetShape(); 720 | 721 | TopoDS_Compound compShape; 722 | BRep_Builder aBuilder; 723 | aBuilder.MakeCompound(compShape); 724 | aBuilder.Add(compShape, rootShape); 725 | 726 | for (const auto& rosette : rosettes) 727 | { 728 | aBuilder.Add(compShape, rosette); 729 | 730 | IShape* iShape = new IShape(rosette); 731 | iShape->SetRosette(true); 732 | 733 | Quantity_ColorRGBA color = Quantity_ColorRGBA(Quantity_Color(1, 1, 1, Quantity_TOC_RGB)); 734 | int rosetteID = m_stepData->GetEntityIDFromShape(rosette); 735 | wstring rosetteName = StrTool::str2wstr(m_stepData->GetEntityNameFromShape(rosette)); 736 | 737 | iShape->AddColor(rosette, color); // White 738 | iShape->SetStepID(rosetteID); // STEP Entity ID 739 | iShape->SetName(rosetteName); // STEP Entity Name 740 | 741 | rootComp->AddIShape(iShape); 742 | } 743 | 744 | rootComp->SetShape(compShape); 745 | } 746 | 747 | void STEP_Reader::AddSectionCaps(Component*& rootComp) 748 | { 749 | if (!m_opt->SectionCap()) 750 | return; 751 | 752 | vector comps; 753 | rootComp->GetLeafComponents(comps); 754 | 755 | vector planeShapes; 756 | m_stepData->AddSectionPlanes(planeShapes); 757 | 758 | TopoDS_Shape rootShape = rootComp->GetShape(); 759 | 760 | TopoDS_Compound compShape; 761 | BRep_Builder aBuilder; 762 | aBuilder.MakeCompound(compShape); 763 | aBuilder.Add(compShape, rootShape); 764 | 765 | for (const auto& planeShape : planeShapes) 766 | { 767 | for (const auto& comp : comps) 768 | { 769 | TopoDS_Shape shape = comp->GetTransformedShape(); 770 | 771 | //if (comp->IsCopy()) 772 | // shape = comp->GetTransformedShape(); 773 | //else 774 | // shape = comp->GetShape(); 775 | 776 | if (!OCCUtil::HasFace(shape)) 777 | continue; 778 | 779 | TopoDS_Shape capShape; 780 | 781 | try { 782 | BRepAlgoAPI_Common common(shape, planeShape); 783 | capShape = common.Shape(); 784 | 785 | if (!OCCUtil::HasFace(capShape)) 786 | continue; 787 | 788 | aBuilder.Add(compShape, capShape); 789 | 790 | IShape* iCapShape = new IShape(capShape); 791 | iCapShape->SetSectionCap(true); 792 | 793 | Quantity_ColorRGBA color; 794 | color = Quantity_ColorRGBA(Quantity_Color(0.65, 0.65, 0.7, Quantity_TOC_RGB)); 795 | 796 | int planeID = m_stepData->GetEntityIDFromShape(planeShape); 797 | wstring planeName = StrTool::str2wstr(m_stepData->GetEntityNameFromShape(planeShape)); 798 | 799 | iCapShape->AddColor(capShape, color); 800 | iCapShape->SetStepID(planeID); // STEP Entity ID 801 | iCapShape->SetName(planeName); // STEP Entity Name 802 | 803 | rootComp->AddIShape(iCapShape); 804 | } 805 | catch (...) { 806 | } 807 | } 808 | } 809 | 810 | rootComp->SetShape(compShape); 811 | } 812 | -------------------------------------------------------------------------------- /STP2X3D/STEP_Reader.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | class STEP_Data; 4 | class Model; 5 | class Component; 6 | class IShape; 7 | 8 | class STEP_Reader 9 | { 10 | public: 11 | STEP_Reader(S2X_Option* opt); 12 | ~STEP_Reader(void); 13 | 14 | bool ReadSTEP(Model* model); 15 | 16 | protected: 17 | void AddSubComponents(Component*& comp, const TDF_Label& label); 18 | void GetSubShapes(const TopoDS_Shape& shape, vector& subShapes) const; 19 | const wstring GetName(const TDF_Label& label) const; 20 | 21 | void AddColors(IShape*& iShape) const; 22 | 23 | bool CheckReturnStatus(const IFSelect_ReturnStatus& status) const; 24 | bool IsEmpty(const TopoDS_Shape& shape) const; 25 | bool IsCopy(Component*& comp); 26 | 27 | void UpdateColorOption() const; 28 | void Clear(void); 29 | 30 | void ReadGDT(Model*& model) const; 31 | void AddRosettes(Component*& rootComp); 32 | void AddSectionCaps(Component*& rootComp); 33 | 34 | private: 35 | S2X_Option* m_opt; 36 | 37 | Handle(XCAFDoc_ShapeTool) m_shapeTool; 38 | Handle(XCAFDoc_ColorTool) m_colorTool; 39 | Handle(XCAFDoc_DimTolTool) m_gdtTool; 40 | Handle(XCAFDoc_ViewTool) m_viewTool; 41 | Handle(XCAFDoc_NotesTool) m_noteTool; 42 | 43 | Quantity_ColorRGBA m_defaultFaceColor; 44 | Quantity_ColorRGBA m_defaultWireColor; 45 | 46 | unordered_map m_idComponentMap; 47 | 48 | STEP_Data* m_stepData; 49 | }; 50 | -------------------------------------------------------------------------------- /STP2X3D/STP2X3D.cpp: -------------------------------------------------------------------------------- 1 | // STP2X3D.cpp : Defines the entry point for the console application. 2 | // 3 | 4 | #include "stdafx.h" 5 | #include "STEP_Reader.h" 6 | #include "Tessellator.h" 7 | #include "X3D_Writer.h" 8 | #include "StatsPrinter.h" 9 | #include "GDT_Item.h" 10 | #include "Mesh.h" 11 | //#include 12 | //#include 13 | 14 | namespace fs = std::experimental::filesystem; 15 | //namespace fs = std::filesystem; 16 | 17 | void Test(S2X_Option* opt) 18 | { 19 | Model* model = new Model(); 20 | 21 | /** START_STEP **/ 22 | wcout << "Reading a STEP file.." << endl; 23 | STEP_Reader sr(opt); 24 | if (!sr.ReadSTEP(model)) 25 | { 26 | delete model; 27 | return; 28 | } 29 | /** END_STEP **/ 30 | 31 | vector comps; 32 | model->GetAllComponents(comps); 33 | 34 | ofstream fout; 35 | fout.open("C:\\Users\\User\\Desktop\\Result.txt"); 36 | 37 | for (const auto& comp : comps) 38 | { 39 | for (int i = 0; i < comp->GetIShapeSize(); ++i) 40 | { 41 | IShape* iShape = comp->GetIShapeAt(i); 42 | const TopoDS_Shape& shape = iShape->GetShape(); 43 | 44 | for (double k = 0.349065; k <= 0.349066; k = k + 0.0000001) 45 | { 46 | OCCUtil::TessellateShape(shape, 0.5, true, k, true); 47 | 48 | int triCount = 0; 49 | 50 | TopExp_Explorer ExpFace; 51 | for (ExpFace.Init(shape, TopAbs_FACE); ExpFace.More(); ExpFace.Next()) 52 | { 53 | const TopoDS_Face& face = TopoDS::Face(ExpFace.Current()); 54 | 55 | TopLoc_Location loc; 56 | 57 | const Handle(Poly_Triangulation)& myT = BRep_Tool::Triangulation(face, loc); 58 | 59 | // Skip if triangulation has failed 60 | if (!myT 61 | || myT.IsNull()) 62 | continue; 63 | 64 | triCount = triCount + myT->NbTriangles(); 65 | } 66 | 67 | fout << k << "\t" << triCount << endl; 68 | } 69 | 70 | } 71 | } 72 | 73 | fout.close(); 74 | } 75 | 76 | // Print out the usage 77 | void PrintUsage(wstring exe, S2X_Option* opt) 78 | { 79 | wcout << endl; 80 | wcout << "//////////////////////////////////////////////////" << endl; 81 | wcout << "// NIST STEP to X3D Translator (STP2X3D) " << opt->Version() <<" //" << endl; 82 | wcout << "//////////////////////////////////////////////////" << endl; 83 | wcout << endl; 84 | wcout << "[Usage]" << endl; 85 | wcout << " " << exe << " option1 value1 option2 value2.." << endl; 86 | wcout << endl; 87 | wcout << "[Options]" << endl; 88 | wcout << " --input Input STEP file path" << endl; 89 | wcout << " --output Output STEP file path (Input name is used if empty)" << endl; 90 | wcout << " --normal Normal vector (1:yes, 0:no) default=" << opt->Normal() << endl; 91 | wcout << " --color Color (1:yes, 0:no) default=" << opt->Color() << endl; 92 | wcout << " --edge Boundary edges (1:yes, 0:no) default=" << opt->Edge() << endl; 93 | wcout << " --sketch Sketch geometry (1:yes, 0:no) default=" << opt->Sketch() << endl; 94 | wcout << " --html Output file type (1:html, 0:x3d) default=" << opt->Html() << endl; 95 | wcout << " --quality Mesh quality (1-low to 10-high) default=" << opt->Quality() << endl; 96 | wcout << " --gdt Geometric elements related to GD&T (1:yes, 0:no) default=" << opt->GDT() << endl; 97 | wcout << " --tess Adaptive tessellation per each body (1:yes, 0:no) default=" << opt->Tessellation() << endl; 98 | wcout << " --rosette Rosette used for Composite Design (1:yes, 0:no) default=" << opt->Rosette() << endl; 99 | wcout << " --cap Cap geometries for sections (1:yes, 0:no) default=" << opt->SectionCap() << endl; 100 | wcout << " --tsolid Tessellated solids (1:yes, 0:no) default=" << opt->TessSolid() << endl; 101 | wcout << " --batch Processing multiple STEP files (1:include sub-directories, 0:current dir)" << endl; 102 | wcout << " Followed by a folder path (e.g. --batch 0 c:\\)" << endl; 103 | wcout << endl; 104 | wcout << "[Examples]" << endl; 105 | wcout << " " << exe << " --input Model.stp --edge 1 --quality 7" << endl; 106 | wcout << " " << exe << " --html 1 --sketch 0 --input Model.step" << endl; 107 | wcout << " " << exe << " --color 0 --batch 1 C:\\Folder --normal 1" << endl; 108 | wcout << endl; 109 | wcout << "[Disclaimers]" << endl; 110 | wcout << " This software was developed at the National Institute of Standards and Technology by" << endl; 111 | wcout << " employees of the Federal Government in the course of their official duties. Pursuant" << endl; 112 | wcout << " to Title 17 Section 105 of the United States Code this software is not subject to" << endl; 113 | wcout << " copyright protection and is in the public domain. This software is an experimental" << endl; 114 | wcout << " system. NIST assumes no responsibility whatsoever for its use by other parties, and" << endl; 115 | wcout << " makes no guarantees, expressed or implied, about its quality, reliability, or any" << endl; 116 | wcout << " other characteristic. NIST Disclaimer : https://www.nist.gov/disclaimer" << endl; 117 | wcout << endl; 118 | wcout << " This software is provided by NIST as a public service. You may use, copy and" << endl; 119 | wcout << " distribute copies of the software in any medium, provided that you keep intact this" << endl; 120 | wcout << " entire notice. You may improve, modify and create derivative works of the software" << endl; 121 | wcout << " or any portion of the software, and you may copy and distribute such modifications" << endl; 122 | wcout << " or works. Modified works should carry a notice stating that you changed the software" << endl; 123 | wcout << " and should note the date and nature of any such change. Please explicitly" << endl; 124 | wcout << " acknowledge NIST as the source of the software." << endl; 125 | wcout << endl; 126 | wcout << "[Credits]" << endl; 127 | wcout << " -The translator is based on the Open CASCADE STEP Processor" << endl; 128 | wcout << " (See https://dev.opencascade.org/doc/overview/html/occt_user_guides__step.html)" << endl; 129 | wcout << " -Developed and managed by Soonjo Kwon, former NIST associate" << endl; 130 | } 131 | 132 | // Set option values 133 | bool SetOption(int argc, char * argv[], S2X_Option* opt) 134 | { 135 | // Print out usage 136 | if (argc < 2) 137 | { 138 | string a = argv[0]; 139 | wstring aw = StrTool::s2ws(a); 140 | 141 | PrintUsage(aw, opt); 142 | //cout << "WRONG USAGE" << std::endl; 143 | return false; 144 | } 145 | 146 | bool inputFlag = false; 147 | bool batchFlag = false; 148 | 149 | // Set options 150 | for (int i = 1; i < argc; ++i) 151 | { 152 | string stoken(argv[i]); 153 | wstring token = StrTool::s2ws(stoken); 154 | 155 | string stoken1(argv[i + 1]); 156 | wstring token1 = StrTool::s2ws(stoken1); 157 | 158 | //wcout << token << L" " << token1 << endl; 159 | 160 | if (token != L"--input" 161 | && token != L"--output" 162 | && token != L"--normal" 163 | && token != L"--color" 164 | && token != L"--edge" 165 | && token != L"--sketch" 166 | && token != L"--html" 167 | && token != L"--quality" 168 | && token != L"--gdt" 169 | && token != L"--batch" 170 | && token != L"--sfa" 171 | && token != L"--tess" 172 | && token != L"--cap" 173 | && token != L"--rosette" 174 | && token != L"--tsolid") 175 | { 176 | wcout << "No such option: " << token << endl; 177 | return false; 178 | } 179 | else 180 | { 181 | if (argc == i + 1 182 | || (token == L"--batch" && argc == i + 2)) 183 | { 184 | wcout << "No value for the option: " << token << endl; 185 | return false; 186 | } 187 | else 188 | { 189 | if (token == L"--input") 190 | { 191 | inputFlag = true; 192 | opt->SetInput(token1); 193 | } 194 | else if (token == L"--output") 195 | { 196 | opt->SetOutput(token1); 197 | } 198 | else if (token == L"--normal") 199 | { 200 | int normal = stoi(token1); 201 | opt->SetNormal(normal); 202 | 203 | if (normal != 0 204 | && normal != 1) 205 | { 206 | wcout << "normal must be either 0 or 1." << endl; 207 | return false; 208 | } 209 | } 210 | else if (token == L"--color") 211 | { 212 | int color = stoi(token1); 213 | opt->SetColor(color); 214 | 215 | if (color != 0 216 | && color != 1) 217 | { 218 | wcout << "color must be either 0 or 1." << endl; 219 | return false; 220 | } 221 | } 222 | else if (token == L"--edge") 223 | { 224 | int edge = stoi(token1); 225 | opt->SetEdge(edge); 226 | 227 | if (edge != 0 228 | && edge != 1) 229 | { 230 | wcout << "edge must be either 0 or 1." << endl; 231 | return false; 232 | } 233 | } 234 | else if (token == L"--sketch") 235 | { 236 | int sketch = stoi(token1); 237 | opt->SetSketch(sketch); 238 | 239 | if (sketch != 0 240 | && sketch != 1) 241 | { 242 | wcout << "sketch must be either 0 or 1." << endl; 243 | return false; 244 | } 245 | } 246 | else if (token == L"--html") 247 | { 248 | int html = stoi(token1); 249 | opt->SetHtml(html); 250 | 251 | if (html != 0 252 | && html != 1) 253 | { 254 | wcout << "html must be either 0 or 1." << endl; 255 | return false; 256 | } 257 | } 258 | else if (token == L"--gdt") 259 | { 260 | int gdt = stoi(token1); 261 | opt->SetGDT(gdt == 1 ? true : false); 262 | 263 | if (gdt != 0 264 | && gdt != 1) 265 | { 266 | wcout << "gdt must be either 0 or 1." << endl; 267 | return false; 268 | } 269 | } 270 | else if (token == L"--sfa") 271 | { 272 | int sfa = stoi(token1); 273 | opt->SetSFA(sfa == 1 ? true : false); 274 | 275 | if (sfa != 0 276 | && sfa != 1) 277 | { 278 | wcout << "sfa must be either 0 or 1." << endl; 279 | return false; 280 | } 281 | } 282 | else if (token == L"--tess") 283 | { 284 | int tess = stoi(token1); 285 | opt->SetTessellation(tess); 286 | 287 | if (tess != 0 288 | && tess != 1) 289 | { 290 | wcout << "tess must be either 0 or 1." << endl; 291 | return false; 292 | } 293 | } 294 | else if (token == L"--rosette") 295 | { 296 | int rosette = stoi(token1); 297 | opt->SetRosette(rosette == 1 ? true : false); 298 | 299 | if (rosette != 0 300 | && rosette != 1) 301 | { 302 | wcout << "rosette must be either 0 or 1." << endl; 303 | return false; 304 | } 305 | } 306 | else if (token == L"--cap") 307 | { 308 | int cap = stoi(token1); 309 | opt->SetSectionCap(cap == 1 ? true : false); 310 | 311 | if (cap != 0 312 | && cap != 1) 313 | { 314 | wcout << "cap must be either 0 or 1." << endl; 315 | return false; 316 | } 317 | } 318 | else if (token == L"--tsolid") 319 | { 320 | int tsolid = stoi(token1); 321 | opt->SetTessSolid(tsolid == 1 ? true : false); 322 | 323 | if (tsolid != 0 324 | && tsolid != 1) 325 | { 326 | wcout << "tsolid must be either 0 or 1." << endl; 327 | return false; 328 | } 329 | } 330 | else if (token == L"--quality") 331 | { 332 | double quality = stof(token1); 333 | opt->SetQuality(quality); 334 | 335 | if (quality < 1.0 336 | || quality > 10.0) 337 | { 338 | wcout << "quality must be between 1 and 10." << endl; 339 | return false; 340 | } 341 | } 342 | else if (token == L"--batch") 343 | { 344 | batchFlag = true; 345 | int batch = stoi(token1); 346 | 347 | string stoken2(argv[i + 2]); 348 | wstring token2 = StrTool::s2ws(stoken2); 349 | 350 | wstring input = token2; 351 | ++i; 352 | 353 | opt->SetBatch(batch); 354 | opt->SetInput(input); 355 | 356 | if (batch != 0 357 | && batch != 1) 358 | { 359 | wcout << "batch must be either 0 or 1." << endl; 360 | return false; 361 | } 362 | } 363 | 364 | ++i; 365 | } 366 | } 367 | } 368 | 369 | // Check flags 370 | if (inputFlag 371 | && batchFlag) 372 | { 373 | wcout << "--input and --batch cannot be used at the same time." << endl; 374 | return false; 375 | } 376 | 377 | // Check input path 378 | if (opt->Input().empty()) 379 | { 380 | wcout << "Please input a STEP file." << endl; 381 | return false; 382 | } 383 | else if (!fs::is_directory(opt->Input()) 384 | && !fs::is_regular_file(opt->Input())) 385 | { 386 | wcout << "No such file or directory: " << opt->Input() << endl; 387 | return false; 388 | } 389 | 390 | return true; 391 | } 392 | 393 | // Run STEP to X3D translation given parameters 394 | int RunSTP2X3D(S2X_Option* opt) 395 | { 396 | Model* model = new Model(); 397 | 398 | StopWatch sw; 399 | sw.Start(); 400 | 401 | /** START_STEP **/ 402 | wcout << "Reading a STEP file.." << endl; 403 | STEP_Reader sr(opt); 404 | if (!sr.ReadSTEP(model)) 405 | { 406 | delete model; 407 | return -1; 408 | } 409 | /** END_STEP **/ 410 | //sw.Lap(); 411 | 412 | /** START_TESSELLATION **/ 413 | wcout << "Tessellating.." << endl; 414 | Tessellator* ts = new Tessellator(opt); 415 | ts->Tessellate(model); 416 | delete ts; 417 | /** END_TESSELLATION **/ 418 | //sw.Lap(); 419 | 420 | /** START_X3D **/ 421 | wcout << "Writing an X3D file.." << endl; 422 | X3D_Writer xw(opt); 423 | xw.WriteX3D(model); 424 | /** END_X3D **/ 425 | //sw.Lap(); 426 | 427 | /// Print results required for SFA 428 | if (opt->SFA()) 429 | { 430 | StatsPrinter::PrintShapeCount(model); 431 | StatsPrinter::PrintBoundingBox(model, opt); 432 | StatsPrinter::PrintSketchExistence(model); 433 | } 434 | /// 435 | 436 | wcout << "STEP to X3D completed!" << endl; 437 | sw.End(); 438 | 439 | delete model; 440 | 441 | return 0; 442 | } 443 | 444 | // Batch run for STEP files under the given folder path 445 | int BatchRun(S2X_Option* opt) 446 | { 447 | vector paths; 448 | 449 | if (opt->Batch() == 0) // Only given directory 450 | { 451 | for (const auto& entry : fs::directory_iterator(opt->Input())) 452 | paths.push_back(entry.path()); 453 | } 454 | else if (opt->Batch() == 1) // Include subdirectories 455 | { 456 | for (const auto& entry : fs::recursive_directory_iterator(opt->Input())) 457 | paths.push_back(entry.path()); 458 | } 459 | 460 | int status = 0; 461 | 462 | for (const auto& path : paths) 463 | { 464 | wstring ext = path.filename().extension().generic_wstring(); 465 | 466 | if (!(ext == L".stp" || ext == L".STP" 467 | || ext == L".step" || ext == L".STEP" 468 | || ext == L".p21" || ext == L".P21")) 469 | continue; 470 | 471 | wstring inFilePath = path.generic_wstring(); 472 | 473 | S2X_Option tmp_opt(*opt); 474 | tmp_opt.SetInput(inFilePath); 475 | 476 | wcout << "[" << path.filename() << "]" << endl; 477 | status += RunSTP2X3D(&tmp_opt); 478 | } 479 | 480 | paths.clear(); 481 | 482 | return status; 483 | } 484 | 485 | // Main entry function 486 | int main(int argc, char * argv[]) 487 | { 488 | S2X_Option opt; // Option for STEP to X3D translator 489 | 490 | int status = -1; // Translation status 491 | 492 | #if _DEBUG 493 | opt.SetInput(L"C:\\Users\\User\\Desktop\\100LPH RO Machine.step"); 494 | opt.SetNormal(1); 495 | opt.SetColor(1); 496 | opt.SetEdge(1); 497 | opt.SetSketch(1); 498 | opt.SetHtml(1); 499 | opt.SetQuality(7.0); 500 | opt.SetGDT(true); 501 | opt.SetSFA(true); 502 | opt.SetTessellation(0); 503 | opt.SetRosette(false); 504 | opt.SetSectionCap(false); 505 | opt.SetTessSolid(true); 506 | #else 507 | if (!SetOption(argc, argv, &opt)) 508 | return status; 509 | #endif 510 | 511 | //Test(&opt); 512 | //return true; 513 | 514 | if (opt.Batch() == -1) // Translate an input STEP file 515 | status = RunSTP2X3D(&opt); 516 | else // Translate multiple STEP files 517 | status = BatchRun(&opt); 518 | 519 | return status; 520 | } 521 | -------------------------------------------------------------------------------- /STP2X3D/ShapeType.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | enum class ShapeType 4 | { 5 | Sketch_Geom, // A shape has only sketch geometries 6 | Face_Geom, // A shape has only face geometries 7 | Hybrid_Geom // A shape has both sketch and face geometries 8 | }; -------------------------------------------------------------------------------- /STP2X3D/StatsPrinter.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | #include "Model.h" 3 | #include "Component.h" 4 | #include "IShape.h" 5 | 6 | 7 | class StatsPrinter 8 | { 9 | public: 10 | 11 | static void PrintBoundingBox(Model* model, S2X_Option* opt) 12 | { 13 | Bnd_Box bndBox; 14 | 15 | // Compute Bounding box for the top-level shape 16 | if ((model->GetShapeType() != ShapeType::Hybrid_Geom 17 | || (model->GetShapeType() == ShapeType::Hybrid_Geom 18 | && opt->Sketch())) 19 | && model->GetRootComponentSize() == 1) 20 | { 21 | const TopoDS_Shape& shape = model->GetRootComponentAt(0)->GetShape(); 22 | bndBox = OCCUtil::ComputeBoundingBox(shape); 23 | bndBox = bndBox.FinitePart(); 24 | } 25 | else 26 | bndBox = model->GetBoundingBox(opt->Sketch()); 27 | 28 | assert(!bndBox.IsVoid()); 29 | 30 | // Bounding boxes are enlarged by the given tolerance 31 | // double tol = 2.5 / opt->Quality(); // before v1.02 (linear deflection for tessellation) 32 | double tol = bndBox.GetGap(); // after v1.02 (gap set by OCC) 33 | 34 | double X_min = 0.0, Y_min = 0.0, Z_min = 0.0; 35 | double X_max = 0.0, Y_max = 0.0, Z_max = 0.0; 36 | 37 | bndBox.Get(X_min, Y_min, Z_min, X_max, Y_max, Z_max); 38 | 39 | // Add and subtract the tolerance 40 | printf("MinXYZ: %.4lf %.4lf %.4lf\n", X_min + tol, Y_min + tol, Z_min + tol); 41 | printf("MaxXYZ: %.4lf %.4lf %.4lf\n", X_max - tol, Y_max - tol, Z_max - tol); 42 | } 43 | 44 | static void PrintShapeCount(Model* model) 45 | { 46 | vector comps; 47 | model->GetAllComponents(comps); 48 | 49 | int shapeCount = 0; 50 | 51 | for (const auto& comp : comps) 52 | shapeCount += comp->GetIShapeSize(); 53 | 54 | comps.clear(); 55 | 56 | printf("Number of Shapes: %d\n", shapeCount); 57 | } 58 | 59 | static void PrintSketchExistence(Model* model) 60 | { 61 | vector comps; 62 | model->GetAllComponents(comps); 63 | 64 | int sketchCount = 0; 65 | int rosetteCount = 0; 66 | 67 | for (const auto& comp : comps) 68 | { 69 | for (int i = 0; i < comp->GetIShapeSize(); ++i) 70 | { 71 | IShape* iShape = comp->GetIShapeAt(i); 72 | 73 | if (iShape->IsSketchGeometry()) 74 | { 75 | if (iShape->IsRosette()) 76 | rosetteCount++; 77 | else 78 | sketchCount++; 79 | } 80 | } 81 | } 82 | 83 | comps.clear(); 84 | 85 | if (sketchCount > 0) 86 | printf("Sketch geometry was found.\n"); 87 | 88 | if (rosetteCount > 0) 89 | printf("Number of Rosettes: %d\n", rosetteCount); 90 | 91 | } 92 | }; -------------------------------------------------------------------------------- /STP2X3D/StopWatch.cpp: -------------------------------------------------------------------------------- 1 | #include "stdafx.h" 2 | #include "StopWatch.h" 3 | 4 | 5 | StopWatch::StopWatch(void) 6 | : m_startTime((clock_t)0.0), 7 | m_endTime((clock_t)0.0) 8 | { 9 | } 10 | 11 | StopWatch::~StopWatch(void) 12 | { 13 | } 14 | 15 | void StopWatch::Start(void) 16 | { 17 | m_netTimes.clear(); 18 | m_startTime = clock(); 19 | } 20 | 21 | void StopWatch::Lap(void) 22 | { 23 | SaveNetTime(); 24 | ReportTime(0); 25 | 26 | m_startTime = clock(); 27 | } 28 | 29 | void StopWatch::End(void) 30 | { 31 | SaveNetTime(); 32 | ReportTime(1); 33 | } 34 | 35 | void StopWatch::SaveNetTime(void) 36 | { 37 | m_endTime = clock(); 38 | 39 | clock_t netTime = m_endTime - m_startTime; 40 | m_netTimes.push_back(netTime); 41 | } 42 | 43 | void StopWatch::ReportTime(int mode) const 44 | { 45 | clock_t time; 46 | 47 | if (mode == 0) 48 | { 49 | time = m_netTimes[m_netTimes.size() - 1]; 50 | cout << "Time elapsed: "; 51 | } 52 | else 53 | { 54 | time = accumulate(m_netTimes.begin(), m_netTimes.end(), 0); 55 | cout << "Total time elapsed: "; 56 | } 57 | 58 | double timeInSec_dbl = time / (double)CLOCKS_PER_SEC; 59 | 60 | int timeInSec_int = (int)timeInSec_dbl; 61 | 62 | if (timeInSec_int < 60) 63 | { 64 | cout << timeInSec_dbl << " seconds" << endl << endl; 65 | } 66 | else if (timeInSec_int < 3600) 67 | { 68 | int minutes = timeInSec_int / 60; 69 | int seconds = timeInSec_int % 60; 70 | 71 | cout << minutes << " minutes "; 72 | 73 | if (seconds > 0) 74 | cout << seconds << " seconds"; 75 | 76 | cout << endl << endl; 77 | } 78 | else 79 | { 80 | int hours = timeInSec_int / 3600; 81 | int minutes = (timeInSec_int % 3600) / 60; 82 | 83 | cout << hours << " hours "; 84 | 85 | if (minutes > 0) 86 | cout << minutes << " minutes"; 87 | 88 | cout << endl << endl; 89 | } 90 | } -------------------------------------------------------------------------------- /STP2X3D/StopWatch.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | class StopWatch 4 | { 5 | public: 6 | StopWatch(void); 7 | ~StopWatch(void); 8 | 9 | void Start(void); 10 | void Lap(void); 11 | void End(void); 12 | 13 | protected: 14 | void SaveNetTime(void); 15 | void ReportTime(int mode) const; 16 | 17 | private: 18 | clock_t m_startTime; 19 | clock_t m_endTime; 20 | vector m_netTimes; 21 | }; -------------------------------------------------------------------------------- /STP2X3D/StrTool.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | class StrTool 4 | { 5 | public: 6 | 7 | static const string ReplaceCharacter(string str, string from, string to) 8 | { 9 | size_t loc = str.find(from); 10 | 11 | while (loc != string::npos) 12 | { 13 | str.replace(loc, from.length(), to); 14 | loc = str.find(from, loc + to.length()); 15 | } 16 | 17 | return str; 18 | } 19 | 20 | static const wstring ReplaceCharacter(wstring str, wstring from, wstring to) 21 | { 22 | size_t loc = str.find(from); 23 | 24 | while (loc != wstring::npos) 25 | { 26 | str.replace(loc, from.length(), to); 27 | loc = str.find(from, loc + to.length()); 28 | } 29 | 30 | return str; 31 | } 32 | 33 | static const wstring RemoveCharacter(wstring str, wstring target) 34 | { 35 | str = ReplaceCharacter(str, target, L""); 36 | 37 | return str; 38 | } 39 | 40 | static const string wstr2str(wstring ws) 41 | { 42 | string s(ws.begin(), ws.end()); 43 | return s; 44 | } 45 | 46 | static const wstring str2wstr(string s) 47 | { 48 | wstring ws(s.begin(), s.end()); 49 | return ws; 50 | } 51 | 52 | // Added by Cabiddu 53 | static const wstring s2ws(const std::string& s) 54 | { 55 | std::string curLocale = setlocale(LC_ALL, ""); 56 | const char* _Source = s.c_str(); 57 | size_t _Dsize = mbstowcs(NULL, _Source, 0) + 1; 58 | wchar_t *_Dest = new wchar_t[_Dsize]; 59 | wmemset(_Dest, 0, _Dsize); 60 | mbstowcs(_Dest,_Source,_Dsize); 61 | std::wstring result = _Dest; 62 | delete []_Dest; 63 | setlocale(LC_ALL, curLocale.c_str()); 64 | return result; 65 | } 66 | 67 | static const wstring u16str2wstr(const u16string& s) 68 | { 69 | wstring_convert, wchar_t> conv; 70 | wstring ws = conv.from_bytes(reinterpret_cast (&s[0]), reinterpret_cast (&s[0] + s.size())); 71 | 72 | return ws; 73 | } 74 | 75 | static const string ToLower(string s) 76 | { 77 | transform(s.begin(), s.end(), s.begin(), ::tolower); 78 | 79 | return s; 80 | } 81 | 82 | static const string ToUpper(string s) 83 | { 84 | transform(s.begin(), s.end(), s.begin(), ::toupper); 85 | 86 | return s; 87 | } 88 | }; 89 | -------------------------------------------------------------------------------- /STP2X3D/Tessellator.cpp: -------------------------------------------------------------------------------- 1 | #include "stdafx.h" 2 | #include "Tessellator.h" 3 | #include "Component.h" 4 | #include "IShape.h" 5 | #include "Mesh.h" 6 | #include "GDT_Item.h" 7 | 8 | Tessellator::Tessellator(S2X_Option* opt) 9 | : m_opt(opt) 10 | { 11 | double angDeflection_max = 0.8, angDeflection_min = 0.2, angDeflection_gap = (angDeflection_max - angDeflection_min) / 10; 12 | m_angDeflection = max(angDeflection_max - (m_opt->Quality() * angDeflection_gap), angDeflection_min); 13 | 14 | //m_linDeflection = 2.5 / m_opt->Quality(); 15 | //m_angDeflection = 5.0 / m_opt->Quality(); 16 | 17 | m_isRelative = false; // If TRUE, linear deflection is automatically set. 18 | } 19 | 20 | Tessellator::~Tessellator(void) 21 | { 22 | } 23 | 24 | void Tessellator::Tessellate(Model*& model) const 25 | { 26 | TessellateModel(model); 27 | 28 | if (m_opt->GDT()) 29 | TessellateGDT(model); 30 | 31 | model->Update(); 32 | } 33 | 34 | void Tessellator::TessellateModel(Model*& model) const 35 | { 36 | if (!m_opt->Tessellation()) 37 | { 38 | for (int i = 0; i < model->GetRootComponentSize(); ++i) 39 | { 40 | Component* rootComp = model->GetRootComponentAt(i); 41 | const TopoDS_Shape& shape = rootComp->GetShape(); 42 | 43 | // Get the relative linear deflection for a shape 44 | double linDeflection = OCCUtil::GetDeflection(shape); 45 | 46 | // Tessellate and add mesh data of a shape 47 | if (!OCCUtil::TessellateShape(shape, linDeflection, m_isRelative, m_angDeflection, true)) 48 | wcout << "\tTessellation has failed on Shape: " << rootComp->GetName() << endl; 49 | } 50 | } 51 | 52 | vector comps; 53 | model->GetAllComponents(comps); 54 | 55 | for (const auto& comp : comps) 56 | { 57 | for (int i = 0; i < comp->GetIShapeSize(); ++i) 58 | { 59 | IShape* iShape = comp->GetIShapeAt(i); 60 | TessellateShape(iShape); 61 | } 62 | } 63 | 64 | comps.clear(); 65 | } 66 | 67 | void Tessellator::TessellateShape(IShape*& iShape) const 68 | { 69 | if (m_opt->Tessellation() 70 | || (m_opt->SFA() 71 | && (iShape->IsRosette() 72 | || iShape->IsSectionCap()))) 73 | { 74 | const TopoDS_Shape& shape = iShape->GetShape(); 75 | 76 | // Get the relative linear deflection for a shape 77 | double linDeflection = OCCUtil::GetDeflection(shape); 78 | 79 | if (m_opt->SFA() // SFA-specific 80 | && (iShape->IsRosette() 81 | || iShape->IsSectionCap())) 82 | linDeflection = 0.1 * linDeflection; 83 | 84 | // Tessellate and add mesh data of a shape 85 | if (!OCCUtil::TessellateShape(shape, linDeflection, m_isRelative, m_angDeflection, true)) 86 | wcout << "\tTessellation has failed on Shape: " << iShape->GetName() << endl; 87 | } 88 | 89 | if (iShape->IsFaceSet()) 90 | AddMeshForFaceSet(iShape); 91 | else 92 | AddMeshForSketchGeometry(iShape); 93 | } 94 | 95 | void Tessellator::AddMeshForFaceSet(IShape*& iShape) const 96 | { 97 | const TopoDS_Shape& shape = iShape->GetShape(); 98 | 99 | // Traverse faces 100 | TopExp_Explorer ExpFace; 101 | for (ExpFace.Init(shape, TopAbs_FACE); ExpFace.More(); ExpFace.Next()) 102 | { 103 | const TopoDS_Face& face = TopoDS::Face(ExpFace.Current()); 104 | Mesh* mesh = GetMeshForFace(face, iShape->IsTessSolidModel()); 105 | 106 | // Save the faceMesh 107 | if (mesh) 108 | iShape->AddMesh(mesh); 109 | } 110 | 111 | iShape->SetTessellated(true); 112 | } 113 | 114 | void Tessellator::AddMeshForSketchGeometry(IShape*& iShape) const 115 | { 116 | const TopoDS_Shape& shape = iShape->GetShape(); 117 | 118 | // Traverse edges 119 | TopExp_Explorer ExpEdge; 120 | for (ExpEdge.Init(shape, TopAbs_EDGE); ExpEdge.More(); ExpEdge.Next()) 121 | { 122 | const TopoDS_Edge& edge = TopoDS::Edge(ExpEdge.Current()); 123 | Mesh* mesh = GetMeshForEdge(edge); 124 | 125 | // Save the edgeMesh 126 | if (mesh) 127 | iShape->AddMesh(mesh); 128 | } 129 | 130 | iShape->SetTessellated(true); 131 | } 132 | 133 | Mesh* Tessellator::GetMeshForFace(const TopoDS_Face& face, bool isTessSolidModel) const 134 | { 135 | TopLoc_Location loc; 136 | 137 | const Handle(Poly_Triangulation)& myT = BRep_Tool::Triangulation(face, loc); 138 | 139 | // Skip if triangulation has failed 140 | if (!myT 141 | || myT.IsNull()) 142 | return nullptr; 143 | 144 | Mesh* mesh = new Mesh(face); 145 | 146 | const Poly_ArrayOfNodes& Nodes = myT->InternalNodes(); 147 | 148 | // Add coordinates 149 | for (int i = Nodes.Lower(); i <= Nodes.Upper(); ++i) 150 | { 151 | const gp_Pnt& pnt = Nodes[i].Transformed(loc.Transformation()); 152 | mesh->AddCoordinate(pnt.XYZ()); 153 | } 154 | 155 | const TopAbs_Orientation& orientation = face.Orientation(); 156 | const Poly_Array1OfTriangle& triangles = myT->InternalTriangles(); 157 | 158 | // Add triangle indexes 159 | for (int i = 1; i <= myT->NbTriangles(); ++i) 160 | { 161 | int n1, n2, n3; 162 | triangles(i).Get(n1, n2, n3); 163 | 164 | // If a face is reversed, change the direction. 165 | if (orientation == TopAbs_REVERSED) 166 | swap(n1, n2); 167 | 168 | if (!IsTriangleValid(Nodes[n1 - 1], Nodes[n2 - 1], Nodes[n3 - 1])) 169 | continue; 170 | 171 | mesh->AddFaceIndex(n1, n2, n3); 172 | 173 | if (m_opt->Normal() 174 | && !isTessSolidModel) 175 | mesh->AddNormalIndex(n1, n2, n3); 176 | } 177 | 178 | // Add vertex normals 179 | if (m_opt->Normal()) 180 | { 181 | if (!isTessSolidModel) 182 | { 183 | BRepGProp_Face gProp(face); 184 | const Poly_ArrayOfUVNodes& uvNodes = myT->InternalUVNodes(); 185 | 186 | for (int i = uvNodes.Lower(); i <= uvNodes.Upper(); ++i) 187 | { 188 | const gp_Pnt2d& uv = uvNodes[i]; 189 | gp_Pnt pnt; 190 | gp_Vec normal; 191 | gProp.Normal(uv.X(), uv.Y(), pnt, normal); 192 | 193 | if (normal.SquareMagnitude() > 0.0) 194 | normal.Normalize(); 195 | 196 | mesh->AddNormal(normal.XYZ()); 197 | } 198 | } 199 | /*else 200 | { 201 | // For tessellated solids 202 | if (m_opt->TessSolid()) 203 | { 204 | int index = 1; 205 | 206 | for (int i = 0; i < mesh->GetFaceIndexSize(); ++i) 207 | { 208 | vector faceIndex = mesh->GetFaceIndexAt(i); 209 | 210 | gp_XYZ p1 = mesh->GetCoordinateAt(faceIndex[0] - 1); 211 | gp_XYZ p2 = mesh->GetCoordinateAt(faceIndex[1] - 1); 212 | gp_XYZ p3 = mesh->GetCoordinateAt(faceIndex[2] - 1); 213 | 214 | gp_XYZ n1 = (p2 - p1).Crossed((p3 - p1)).Normalized(); 215 | gp_XYZ n2 = (p3 - p2).Crossed((p1 - p2)).Normalized(); 216 | gp_XYZ n3 = (p1 - p3).Crossed((p2 - p3)).Normalized(); 217 | 218 | mesh->AddNormal(n1); 219 | mesh->AddNormal(n2); 220 | mesh->AddNormal(n3); 221 | 222 | mesh->AddNormalIndex(index, index + 1, index + 2); 223 | index = index + 3; 224 | } 225 | } 226 | }*/ 227 | } 228 | 229 | // Add boundary edges 230 | if (m_opt->Edge()) 231 | { 232 | if (!isTessSolidModel) 233 | { 234 | TopExp_Explorer ExpEdge; 235 | for (ExpEdge.Init(face, TopAbs_EDGE); ExpEdge.More(); ExpEdge.Next()) 236 | { 237 | const TopoDS_Edge& edge = TopoDS::Edge(ExpEdge.Current()); 238 | const Handle(Poly_PolygonOnTriangulation)& polygon = BRep_Tool::PolygonOnTriangulation(edge, myT, loc); 239 | const TColStd_Array1OfInteger& edgeNodes = polygon->Nodes(); 240 | 241 | vector edgeIndex; 242 | 243 | for (int i = edgeNodes.Lower(); i <= edgeNodes.Upper(); ++i) 244 | edgeIndex.push_back(edgeNodes(i)); 245 | 246 | mesh->AddEdgeIndex(edgeIndex); 247 | edgeIndex.clear(); 248 | } 249 | } 250 | else 251 | { 252 | // For tessellated solids 253 | if (m_opt->TessSolid()) 254 | { 255 | for (int i = 0; i < mesh->GetFaceIndexSize(); ++i) 256 | { 257 | vector faceIndex = mesh->GetFaceIndexAt(i); 258 | 259 | vector edgeIndex1, edgeIndex2, edgeIndex3; 260 | 261 | edgeIndex1.push_back(faceIndex[0]); 262 | edgeIndex1.push_back(faceIndex[1]); 263 | edgeIndex2.push_back(faceIndex[1]); 264 | edgeIndex2.push_back(faceIndex[2]); 265 | edgeIndex3.push_back(faceIndex[2]); 266 | edgeIndex3.push_back(faceIndex[0]); 267 | 268 | mesh->AddEdgeIndex(edgeIndex1); 269 | mesh->AddEdgeIndex(edgeIndex2); 270 | mesh->AddEdgeIndex(edgeIndex3); 271 | } 272 | } 273 | } 274 | } 275 | 276 | return mesh; 277 | } 278 | 279 | Mesh* Tessellator::GetMeshForEdge(const TopoDS_Edge& edge) const 280 | { 281 | TopLoc_Location loc; 282 | 283 | // Get a tessellated edge 284 | const Handle(Poly_Polygon3D)& myP = BRep_Tool::Polygon3D(edge, loc); 285 | 286 | if (!myP 287 | || myP.IsNull()) 288 | return nullptr; 289 | 290 | Mesh* mesh = new Mesh(edge); 291 | 292 | const TColgp_Array1OfPnt& Nodes = myP->Nodes(); 293 | 294 | vector edgeIndex; 295 | 296 | // Add coordinates and edge index 297 | for (int i = Nodes.Lower(); i <= Nodes.Upper(); ++i) 298 | { 299 | const gp_Pnt& pnt = Nodes(i).Transformed(loc.Transformation()); 300 | mesh->AddCoordinate(pnt.XYZ()); 301 | edgeIndex.push_back(i); 302 | } 303 | 304 | // Save the edge index 305 | mesh->AddEdgeIndex(edgeIndex); 306 | edgeIndex.clear(); 307 | 308 | return mesh; 309 | } 310 | 311 | bool Tessellator::IsTriangleValid(const gp_Pnt& p1, const gp_Pnt& p2, const gp_Pnt& p3) const 312 | { 313 | gp_Vec v1(p1, p2); 314 | gp_Vec v2(p2, p3); 315 | gp_Vec v3(p3, p1); 316 | gp_Vec v_norm = v1 ^ v2; 317 | 318 | // Tolerance (1.e-7)^2 319 | double tol = Precision::SquareConfusion(); 320 | 321 | // Valid if the magnitudes are greater than tolerance 322 | if (v1.SquareMagnitude() > tol 323 | && v2.SquareMagnitude() > tol 324 | && v3.SquareMagnitude() > tol 325 | && v_norm.SquareMagnitude() > tol) 326 | return true; 327 | 328 | return false; 329 | } 330 | 331 | void Tessellator::TessellateGDT(Model*& model) const 332 | { 333 | for (int i = 0; i < model->GetGDTSize(); ++i) 334 | { 335 | GDT_Item* gdt = model->GetGDTAt(i); 336 | 337 | for (int j = 0; j < gdt->GetShapeSize(); ++j) 338 | { 339 | const TopoDS_Shape& shape = gdt->GetShapeAt(j); 340 | TopAbs_ShapeEnum shapeType = shape.ShapeType(); 341 | 342 | if (shapeType == TopAbs_FACE) // Find and add the face mesh 343 | { 344 | const TopoDS_Face& face = TopoDS::Face(shape); 345 | Mesh* mesh = GetMeshForFace(face, false); 346 | 347 | // Save the face mesh 348 | if (mesh) 349 | gdt->AddMesh(mesh); 350 | } 351 | else // Tessellate and add the edge mesh 352 | { 353 | double linDeflection = OCCUtil::GetDeflection(shape); 354 | 355 | if (!OCCUtil::TessellateShape(shape, linDeflection, m_isRelative, m_angDeflection, true)) 356 | return; 357 | 358 | TopExp_Explorer ExpEdge; 359 | for (ExpEdge.Init(shape, TopAbs_EDGE); ExpEdge.More(); ExpEdge.Next()) 360 | { 361 | const TopoDS_Edge& edge = TopoDS::Edge(ExpEdge.Current()); 362 | 363 | Mesh* mesh = GetMeshForEdge(edge); 364 | 365 | // Save the edge mesh 366 | if (mesh) 367 | gdt->AddMesh(mesh); 368 | } 369 | } 370 | } 371 | } 372 | } 373 | -------------------------------------------------------------------------------- /STP2X3D/Tessellator.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | class Component; 4 | class Mesh; 5 | class IShape; 6 | class GDT_Item; 7 | 8 | class Tessellator 9 | { 10 | public: 11 | Tessellator(S2X_Option* opt); 12 | ~Tessellator(void); 13 | 14 | void Tessellate(Model*& model) const; 15 | 16 | protected: 17 | void TessellateModel(Model*& model) const; 18 | void TessellateShape(IShape*& iShape) const; 19 | 20 | void AddMeshForFaceSet(IShape*& iShape) const; 21 | void AddMeshForSketchGeometry(IShape*& iShape) const; 22 | 23 | Mesh* GetMeshForFace(const TopoDS_Face& face, bool isTessSolidModel) const; 24 | Mesh* GetMeshForEdge(const TopoDS_Edge& edge) const; 25 | 26 | bool IsTriangleValid(const gp_Pnt& p1, const gp_Pnt& p2, const gp_Pnt& p3) const; 27 | 28 | void TessellateGDT(Model*& model) const; 29 | 30 | private: 31 | S2X_Option* m_opt; 32 | 33 | double m_linDeflection; 34 | double m_angDeflection; 35 | 36 | bool m_isRelative; 37 | }; -------------------------------------------------------------------------------- /STP2X3D/X3D_Writer.cpp: -------------------------------------------------------------------------------- 1 | #include "stdafx.h" 2 | #include "X3D_Writer.h" 3 | #include "Component.h" 4 | #include "IShape.h" 5 | #include "Mesh.h" 6 | #include "GDT_Item.h" 7 | 8 | X3D_Writer::X3D_Writer(S2X_Option* opt) 9 | : m_opt(opt) 10 | { 11 | // Attributes for Appearance nodes 12 | m_diffuseColor.SetValues(0.55, 0.55, 0.6, Quantity_TOC_RGB); 13 | m_emissiveColor.SetValues(1.0, 1.0, 1.0, Quantity_TOC_RGB); 14 | m_specularColor.SetValues(0.2, 0.2, 0.2, Quantity_TOC_RGB); 15 | m_gdtColor.SetValues(0.5, 0.1, 0.1, Quantity_TOC_RGB); 16 | m_gdtColor2.SetValues(0.1, 0.1, 1, Quantity_TOC_RGB); 17 | 18 | m_shininess = 0.9; 19 | m_ambientIntensity = 1.0; 20 | m_transparency = 1.0; 21 | 22 | // Attribute for IndexedFaceSet required for X3DOM webvis 23 | m_creaseAngle = 0.2; 24 | } 25 | 26 | X3D_Writer::~X3D_Writer(void) 27 | { 28 | Clear(); 29 | } 30 | 31 | void X3D_Writer::WriteX3D(Model*& model) 32 | { 33 | wstringstream ss_x3d; 34 | 35 | // Initial indent level 36 | int level = 0; 37 | 38 | // Open header 39 | ss_x3d << OpenHeader(); 40 | 41 | // Write viewpoint 42 | ss_x3d << WriteViewpoint(model, level + 1); 43 | 44 | // Write model 45 | ss_x3d << WriteModel(model, level + 1); 46 | 47 | // Write GDT geometries 48 | if (m_opt->GDT()) 49 | ss_x3d << WriteGDT(model, level + 1); 50 | 51 | // Close header 52 | ss_x3d << CloseHeader(); 53 | 54 | // Write X3D file 55 | wstring filePath = m_opt->Output(); 56 | 57 | wofstream wof; 58 | 59 | // This line is required to write Unicode characters. 60 | wof.imbue(locale(locale::empty(), new codecvt_utf8)); 61 | 62 | wof.open(filePath.c_str()); 63 | wof << ss_x3d.str().c_str(); 64 | wof.close(); 65 | 66 | /// Print results required for SFA 67 | if (m_opt->SFA()) 68 | { 69 | PrintIndentCount(); 70 | PrintMaterialCount(); 71 | } 72 | /// 73 | 74 | ss_x3d.clear(); 75 | } 76 | 77 | wstring X3D_Writer::OpenHeader(void) const 78 | { 79 | wstringstream ss_hd; 80 | 81 | if (m_opt->Html()) 82 | { 83 | ss_hd << "\n"; 84 | ss_hd << "\n"; 85 | //ss_hd << " \n"; 86 | //ss_hd << " \n"; 87 | ss_hd << " \n"; 88 | ss_hd << " \n"; 89 | ss_hd << "\n"; 90 | ss_hd << "\n"; 91 | } 92 | else 93 | { 94 | ss_hd << "\n"; 95 | } 96 | 97 | ss_hd << "\n"; 98 | ss_hd << "\n"; 99 | ss_hd << " \n"; 100 | ss_hd << "\n"; 101 | ss_hd << "\n"; 102 | 103 | return ss_hd.str(); 104 | } 105 | 106 | wstring X3D_Writer::CloseHeader(void) const 107 | { 108 | wstringstream ss_hd; 109 | 110 | ss_hd << "\n"; 111 | ss_hd << ""; 112 | 113 | if (m_opt->Html()) 114 | { 115 | ss_hd << "\n"; 116 | ss_hd << "\n"; 117 | ss_hd << ""; 118 | } 119 | 120 | return ss_hd.str(); 121 | } 122 | 123 | wstring X3D_Writer::WriteViewpoint(Model*& model, int level) const 124 | { 125 | if (!m_opt->Html()) 126 | return L""; 127 | 128 | wstringstream ss_vp; 129 | 130 | Bnd_Box bndBox = model->GetBoundingBox(m_opt->Sketch()); 131 | assert(!bndBox.IsVoid()); 132 | 133 | double X_min = 0.0, Y_min = 0.0, Z_min = 0.0; 134 | double X_max = 0.0, Y_max = 0.0, Z_max = 0.0; 135 | 136 | bndBox.Get(X_min, Y_min, Z_min, X_max, Y_max, Z_max); 137 | 138 | double X_mean = (X_min + X_max) / 2; 139 | double Y_mean = (Y_min + Y_max) / 2; 140 | double Z_mean = (Z_min + Z_max) / 2; 141 | 142 | double X_pos = X_mean; 143 | double Y_pos = Y_mean; 144 | double Z_pos = Z_mean; 145 | 146 | double X_ori = 1.0; 147 | double Y_ori = 0.0; 148 | double Z_ori = 0.0; 149 | double R_ori = PI / 2; 150 | 151 | double X_gap = X_max - X_min; 152 | double Y_gap = Y_max - Y_min; 153 | double Z_gap = Z_max - Z_min; 154 | 155 | if (X_gap >= Y_gap 156 | && X_gap >= Z_gap) 157 | Y_pos = (-2) * X_gap; 158 | else if (Y_gap >= X_gap 159 | && Y_gap >= Z_gap) 160 | Y_pos = (-2) * Y_gap; 161 | else if (Z_gap >= X_gap 162 | && Z_gap >= Y_gap) 163 | Y_pos = (-2) * Z_gap; 164 | 165 | ss_vp << Indent(level); 166 | ss_vp << "\n"; 185 | 186 | return ss_vp.str(); 187 | } 188 | 189 | wstring X3D_Writer::WriteModel(Model*& model, int level) 190 | { 191 | wstringstream ss_model; 192 | 193 | if (model->GetRootComponentSize() >= 2) 194 | { 195 | ss_model << Indent(level); 196 | ss_model << "\n"; 197 | CountIndent(level); 198 | } 199 | else 200 | level--; 201 | 202 | // Write root components 203 | for (int i = 0; i < model->GetRootComponentSize(); ++i) 204 | { 205 | Component* rootComp = model->GetRootComponentAt(i); 206 | 207 | if (m_opt->SFA() // SFA-specific 208 | && rootComp->GetSubComponentSize() == 0 209 | && rootComp->GetIShapeSize() == 1 210 | && rootComp->GetIShapeAt(0)->IsSketchGeometry()) 211 | { 212 | IShape* shape = rootComp->GetIShapeAt(0); 213 | ss_model << WriteSketchGeometry(shape, level + 1); 214 | } 215 | else 216 | { 217 | ss_model << Indent(level + 1); 218 | ss_model << "SFA() 221 | && m_opt->GDT()) 222 | ss_model << " id='geometry'"; 223 | 224 | ss_model << " DEF='" << rootComp->GetName() << "'>\n"; 225 | CountIndent(level + 1); 226 | 227 | ss_model << WriteComponent(rootComp, level + 1); 228 | 229 | ss_model << Indent(level + 1); 230 | ss_model << "\n"; 231 | } 232 | } 233 | 234 | if (model->GetRootComponentSize() >= 2) 235 | { 236 | ss_model << Indent(level); 237 | ss_model << "\n"; 238 | } 239 | 240 | return ss_model.str(); 241 | } 242 | 243 | wstring X3D_Writer::WriteComponent(Component*& comp, int level) 244 | { 245 | wstringstream ss_comp; 246 | 247 | for (int i = 0; i < comp->GetSubComponentSize(); ++i) 248 | { 249 | Component* subComp = comp->GetSubComponentAt(i); 250 | bool isTransformed = OCCUtil::IsTransformed(subComp->GetTransformation()); 251 | 252 | if (isTransformed) 253 | { 254 | ss_comp << Indent(level + 1); 255 | ss_comp << "SFA()) 259 | ss_comp << " id='" << subComp->GetName() << "'"; 260 | 261 | // Transform attributes i.e. Translation and Rotation 262 | ss_comp << WriteTransformAttributes(subComp->GetTransformation()) << ">\n"; 263 | } 264 | else 265 | level--; 266 | 267 | if (subComp->IsCopy()) 268 | { 269 | if (m_opt->SFA() // SFA-specific 270 | && subComp->GetOriginalComponent()->GetSubComponentSize() == 0 271 | && subComp->GetOriginalComponent()->GetIShapeSize() == 1 272 | && subComp->GetOriginalComponent()->GetIShapeAt(0)->IsSketchGeometry()) 273 | { 274 | IShape* shape = subComp->GetOriginalComponent()->GetIShapeAt(0); 275 | ss_comp << WriteSketchGeometry(shape, level + 2); 276 | } 277 | else 278 | { 279 | wstring orgCompName = subComp->GetOriginalComponent()->GetName(); 280 | 281 | ss_comp << Indent(level + 2); 282 | ss_comp << "\n"; 286 | else 287 | ss_comp << "'/>\n"; 288 | 289 | CountIndent(level + 2); 290 | } 291 | } 292 | else 293 | { 294 | if (m_opt->SFA() // SFA-specific 295 | && subComp->GetSubComponentSize() == 0 296 | && subComp->GetIShapeSize() == 1 297 | && subComp->GetIShapeAt(0)->IsSketchGeometry()) 298 | { 299 | IShape* shape = subComp->GetIShapeAt(0); 300 | ss_comp << WriteSketchGeometry(shape, level + 2); 301 | } 302 | else 303 | { 304 | ss_comp << Indent(level + 2); 305 | ss_comp << "SFA() 308 | && subComp->GetStepID() != -1) 309 | ss_comp << " id='msb " << subComp->GetStepID() << "'"; 310 | 311 | ss_comp << " DEF='" << subComp->GetName() << "'>\n"; 312 | CountIndent(level + 2); 313 | 314 | ss_comp << WriteComponent(subComp, level + 2); // Recursive call 315 | 316 | ss_comp << Indent(level + 2); 317 | ss_comp << "\n"; 318 | } 319 | } 320 | 321 | if (isTransformed) 322 | { 323 | ss_comp << Indent(level + 1); 324 | ss_comp << "\n"; 325 | } 326 | else 327 | level++; 328 | } 329 | 330 | // Write shape nodes 331 | for (int i = 0; i < comp->GetIShapeSize(); ++i) 332 | { 333 | IShape* iShape = comp->GetIShapeAt(i); 334 | 335 | if (iShape->IsRosette() 336 | || iShape->IsSectionCap()) 337 | continue; 338 | 339 | try 340 | { 341 | ss_comp << WriteShape(iShape, level + 1); 342 | } 343 | catch (...) 344 | { 345 | wcout << "Writing X3D has failed on Shape: " << iShape->GetName() << endl; 346 | } 347 | } 348 | 349 | if (m_opt->Rosette() 350 | && comp->HasRosette()) 351 | ss_comp << WriteRosetteGeometry(comp, level + 1); 352 | 353 | if (m_opt->SectionCap() 354 | && comp->HasSectionCap()) 355 | ss_comp << WriteSectionCapGeometry(comp, level + 1); 356 | 357 | return ss_comp.str(); 358 | } 359 | 360 | wstring X3D_Writer::WriteTransformAttributes(const gp_Trsf& trsf) const 361 | { 362 | wstringstream ss_trsf; 363 | 364 | if (OCCUtil::IsTranslated(trsf)) 365 | { 366 | const gp_XYZ& trans = trsf.TranslationPart(); 367 | 368 | ss_trsf << " translation='"; 369 | ss_trsf << NumTool::DoubleToWString(trans.X()) << " "; 370 | ss_trsf << NumTool::DoubleToWString(trans.Y()) << " "; 371 | ss_trsf << NumTool::DoubleToWString(trans.Z()) << "'"; 372 | } 373 | 374 | if (OCCUtil::IsRotated(trsf)) 375 | { 376 | gp_Vec rotAxis; 377 | double rotAngle = 0.0; 378 | trsf.GetRotation().GetVectorAndAngle(rotAxis, rotAngle); 379 | 380 | ss_trsf << " rotation='"; 381 | ss_trsf << NumTool::DoubleToWString(rotAxis.X()) << " "; 382 | ss_trsf << NumTool::DoubleToWString(rotAxis.Y()) << " "; 383 | ss_trsf << NumTool::DoubleToWString(rotAxis.Z()) << " "; 384 | ss_trsf << NumTool::DoubleToWString(rotAngle) << "'"; 385 | } 386 | 387 | return ss_trsf.str(); 388 | } 389 | 390 | wstring X3D_Writer::WriteShape(IShape*& iShape, int level) 391 | { 392 | wstringstream ss_shape; 393 | 394 | if (iShape->IsFaceSet()) 395 | { 396 | wstring shapeId = iShape->GetUniqueName(); 397 | 398 | ss_shape << Indent(level); 399 | ss_shape << "SFA()) 402 | ss_shape << " id='" << shapeId << "'"; 403 | 404 | ss_shape << " DEF='" << iShape->GetName() << "'"; 405 | ss_shape << ">\n"; 406 | 407 | ss_shape << WriteIndexedFaceSet(iShape, level + 1); 408 | 409 | ss_shape << Indent(level); 410 | ss_shape << "\n"; 411 | 412 | if (m_opt->Edge()) // Boundary edges 413 | { 414 | ss_shape << Indent(level); 415 | ss_shape << "SFA()) 418 | ss_shape << " id='" << shapeId << "'"; 419 | 420 | ss_shape << " DEF='" << iShape->GetName() << "_edges'"; 421 | ss_shape << ">\n"; 422 | 423 | ss_shape << WriteIndexedLineSet(iShape, level + 1); 424 | 425 | ss_shape << Indent(level); 426 | ss_shape << "\n"; 427 | } 428 | } 429 | else // Sketch geometry 430 | { 431 | ss_shape << Indent(level); 432 | ss_shape << "SFA() 435 | && iShape->GetStepID() != -1 436 | && iShape->IsRosette()) 437 | ss_shape << " id='curve 11 " << iShape->GetStepID() << "'"; 438 | 439 | if (!m_opt->SFA()) 440 | ss_shape << " DEF='" << iShape->GetName() << "'"; 441 | 442 | ss_shape << ">\n"; 443 | 444 | ss_shape << WriteIndexedLineSet(iShape, level + 1); 445 | 446 | ss_shape << Indent(level); 447 | ss_shape << "\n"; 448 | } 449 | 450 | return ss_shape.str(); 451 | } 452 | 453 | wstring X3D_Writer::WriteIndexedFaceSet(IShape*& iShape, int level) 454 | { 455 | wstringstream ss_ifs; 456 | 457 | bool isMultiColored = iShape->IsMultiColored(); 458 | bool isSingleTransparent = iShape->IsSingleTransparent(); 459 | double transparency = m_transparency; 460 | 461 | // Write Appearance node 462 | ss_ifs << Indent(level); 463 | 464 | if (isMultiColored) // No diffuse color 465 | { 466 | if (isSingleTransparent) 467 | transparency = 1.0 - iShape->GetColor().Alpha(); 468 | 469 | ss_ifs << WriteAppearance(iShape, m_diffuseColor, false, 470 | m_emissiveColor, false, 471 | m_specularColor, true, 472 | m_shininess, true, 473 | m_ambientIntensity, false, 474 | transparency, isSingleTransparent); 475 | } 476 | else 477 | { 478 | Quantity_ColorRGBA color(m_diffuseColor); 479 | 480 | if (m_opt->Color()) 481 | color = iShape->GetColor(); // Set diffuse color 482 | 483 | if (isSingleTransparent) 484 | transparency = 1.0 - color.Alpha(); 485 | 486 | ss_ifs << WriteAppearance(iShape, color.GetRGB(), true, 487 | m_emissiveColor, false, 488 | m_specularColor, true, 489 | m_shininess, true, 490 | m_ambientIntensity, false, 491 | transparency, isSingleTransparent); 492 | } 493 | 494 | bool isSectionCap = iShape->IsSectionCap(); 495 | bool isTessSolidModel = iShape->IsTessSolidModel(); 496 | 497 | // Open IndexedFaceSet 498 | ss_ifs << Indent(level); 499 | ss_ifs << "Normal() 502 | && !isTessSolidModel) 503 | ss_ifs << " creaseAngle='" << NumTool::DoubleToWString(m_creaseAngle) << "'"; 504 | 505 | ss_ifs << " solid='false'"; 506 | 507 | ss_ifs << WriteCoordinateIndex(iShape, true); 508 | 509 | if (m_opt->Normal() 510 | && !isSectionCap 511 | && !isTessSolidModel) 512 | ss_ifs << WriteNormalIndex(iShape); 513 | 514 | ss_ifs << ">\n"; 515 | 516 | // Write coordinates 517 | ss_ifs << Indent(level + 1); 518 | ss_ifs << WriteCoordinate(iShape, false); 519 | 520 | // Write normals 521 | if (m_opt->Normal() 522 | && !isSectionCap 523 | && !isTessSolidModel) 524 | { 525 | ss_ifs << Indent(level + 1); 526 | ss_ifs << WriteNormal(iShape); 527 | } 528 | 529 | // Write colors 530 | if (isMultiColored) 531 | { 532 | ss_ifs << Indent(level + 1); 533 | ss_ifs << WriteColor(iShape); 534 | } 535 | 536 | // Close IndexedFaceSet 537 | ss_ifs << Indent(level); 538 | ss_ifs << "\n"; 539 | 540 | return ss_ifs.str(); 541 | } 542 | 543 | wstring X3D_Writer::WriteIndexedLineSet(IShape*& iShape, int level) 544 | { 545 | wstringstream ss_ils; 546 | 547 | bool isMultiColored = iShape->IsMultiColored(); 548 | 549 | // Write Appearance node 550 | if (iShape->IsSketchGeometry()) 551 | { 552 | if (!isMultiColored) 553 | { 554 | Quantity_ColorRGBA color(m_emissiveColor); 555 | 556 | if (m_opt->Color()) 557 | color = iShape->GetColor(); 558 | 559 | ss_ils << Indent(level); 560 | ss_ils << WriteAppearance(iShape, m_diffuseColor, false, 561 | color.GetRGB(), true, 562 | m_specularColor, false, 563 | m_shininess, false, 564 | m_ambientIntensity, false, 565 | m_transparency, false); 566 | } 567 | } 568 | else 569 | { 570 | Quantity_Color color(0.0, 0.0, 0.0, Quantity_TOC_RGB); 571 | 572 | ss_ils << Indent(level); 573 | ss_ils << WriteAppearance(iShape, m_diffuseColor, false, 574 | color, true, 575 | m_specularColor, false, 576 | m_shininess, false, 577 | m_ambientIntensity, false, 578 | m_transparency, false); 579 | } 580 | 581 | // Open IndexedLineSet 582 | ss_ils << Indent(level); 583 | ss_ils << "\n"; 585 | 586 | // Write coordinates 587 | ss_ils << Indent(level + 1); 588 | 589 | if (iShape->IsSketchGeometry()) 590 | ss_ils << WriteCoordinate(iShape, false); 591 | else 592 | ss_ils << WriteCoordinate(iShape, true); 593 | 594 | // Write colors 595 | if (iShape->IsSketchGeometry() 596 | && isMultiColored) 597 | { 598 | ss_ils << Indent(level + 1); 599 | ss_ils << WriteColor(iShape); 600 | } 601 | 602 | // Close IndexedLineSet 603 | ss_ils << Indent(level); 604 | ss_ils << "\n"; 605 | 606 | return ss_ils.str(); 607 | } 608 | 609 | wstring X3D_Writer::WriteAppearance(IShape*& iShape, const Quantity_Color& diffuseColor, bool isDiffuseOn, 610 | const Quantity_Color& emissiveColor, bool isEmissiveOn, 611 | const Quantity_Color& specularColor, bool isSpecularOn, 612 | double& shininess, bool isShininessOn, 613 | double& ambientIntensity, bool isAmbientIntensityOn, 614 | double& transparency, bool isTransparencyOn) 615 | { 616 | wstringstream ss_app; 617 | 618 | int appID = 0; 619 | 620 | //if (!m_opt->SFA() 621 | // || (m_opt->SFA() 622 | // && iShape->IsFaceSet())) 623 | //{ 624 | if (CheckSameAppearance(diffuseColor, isDiffuseOn, 625 | emissiveColor, isEmissiveOn, 626 | specularColor, isSpecularOn, 627 | shininess, isShininessOn, 628 | ambientIntensity, isAmbientIntensityOn, 629 | transparency, isTransparencyOn, 630 | appID)) 631 | { 632 | ss_app << "\n"; 633 | 634 | return ss_app.str(); 635 | } 636 | //} 637 | 638 | // Write Appearance node 639 | ss_app << "SFA() 642 | // || (m_opt->SFA() 643 | // && iShape->IsFaceSet())) 644 | ss_app << " DEF='app" << to_wstring(appID) << "'"; 645 | 646 | ss_app << ">SFA() 649 | //&& iShape->IsFaceSet() 650 | ) 651 | ss_app << " id='mat" << to_wstring(appID) << "'"; 652 | 653 | if (isDiffuseOn) 654 | { 655 | ss_app << " diffuseColor='"; 656 | ss_app << NumTool::DoubleToWString(diffuseColor.Red()) << " "; 657 | ss_app << NumTool::DoubleToWString(diffuseColor.Green()) << " "; 658 | ss_app << NumTool::DoubleToWString(diffuseColor.Blue()) << "'"; 659 | } 660 | 661 | if (isEmissiveOn) 662 | { 663 | ss_app << " emissiveColor='"; 664 | ss_app << NumTool::DoubleToWString(emissiveColor.Red()) << " "; 665 | ss_app << NumTool::DoubleToWString(emissiveColor.Green()) << " "; 666 | ss_app << NumTool::DoubleToWString(emissiveColor.Blue()) << "'"; 667 | } 668 | 669 | if (isSpecularOn) 670 | { 671 | ss_app << " specularColor='"; 672 | ss_app << NumTool::DoubleToWString(specularColor.Red()) << " "; 673 | ss_app << NumTool::DoubleToWString(specularColor.Green()) << " "; 674 | ss_app << NumTool::DoubleToWString(specularColor.Blue()) << "'"; 675 | } 676 | 677 | if (isShininessOn) 678 | { 679 | ss_app << " shininess='"; 680 | ss_app << NumTool::DoubleToWString(shininess) << "'"; 681 | } 682 | 683 | if (isAmbientIntensityOn) 684 | { 685 | ss_app << " ambientIntensity='"; 686 | ss_app << NumTool::DoubleToWString(ambientIntensity) << "'"; 687 | } 688 | 689 | if (isTransparencyOn) 690 | { 691 | ss_app << " transparency='"; 692 | ss_app << NumTool::DoubleToWString(transparency) << "'"; 693 | } 694 | 695 | ss_app << ">\n"; 696 | 697 | return ss_app.str(); 698 | } 699 | 700 | wstring X3D_Writer::WriteCoordinate(IShape*& iShape, bool isBoundaryEdges) const 701 | { 702 | wstringstream ss_coords; 703 | 704 | ss_coords << "Edge() 709 | && iShape->IsFaceSet()) 710 | ss_coords << " DEF='c" << to_wstring(iShape->GetGlobalIndex()) << "'"; 711 | 712 | ss_coords << " point='"; 713 | 714 | for (int i = 0; i < iShape->GetMeshSize(); ++i) 715 | { 716 | Mesh* mesh = iShape->GetMeshAt(i); 717 | 718 | for (int j = 0; j < mesh->GetCoordinateSize(); ++j) 719 | { 720 | const gp_XYZ& coord = mesh->GetCoordinateAt(j); 721 | 722 | ss_coords << NumTool::DoubleToWString(coord.X()) << " "; 723 | ss_coords << NumTool::DoubleToWString(coord.Y()) << " "; 724 | ss_coords << NumTool::DoubleToWString(coord.Z()) << " "; 725 | } 726 | } 727 | } 728 | else 729 | { 730 | ss_coords << " USE='c" << to_wstring(iShape->GetGlobalIndex()); 731 | } 732 | 733 | if (m_opt->SFA()) 734 | ss_coords << "'>\n"; 735 | else 736 | ss_coords << "'/>\n"; 737 | 738 | return CleanString(ss_coords.str()); 739 | } 740 | 741 | wstring X3D_Writer::WriteCoordinateIndex(IShape*& iShape, bool faceMesh) const 742 | { 743 | wstringstream ss_coordIndex; 744 | ss_coordIndex << " coordIndex='"; 745 | 746 | int prevCoordCount = 0; // The number of previous coordinates 747 | 748 | for (int i = 0; i < iShape->GetMeshSize(); ++i) 749 | { 750 | Mesh* mesh = iShape->GetMeshAt(i); 751 | 752 | if (faceMesh) // Face mesh 753 | { 754 | // Traverse triangles 755 | for (int j = 0; j < mesh->GetFaceIndexSize(); ++j) 756 | { 757 | const vector& faceIndex = mesh->GetFaceIndexAt(j); 758 | 759 | ss_coordIndex << to_wstring(faceIndex[0] - 1 + prevCoordCount) << " "; 760 | ss_coordIndex << to_wstring(faceIndex[1] - 1 + prevCoordCount) << " "; 761 | ss_coordIndex << to_wstring(faceIndex[2] - 1 + prevCoordCount) << " "; 762 | ss_coordIndex << "-1 "; 763 | } 764 | } 765 | else // Edge mesh (Boundary edges, sketch geometry) 766 | { 767 | // Traverse edges 768 | for (int j = 0; j < mesh->GetEdgeIndexSize(); ++j) 769 | { 770 | const vector& edgeIndex = mesh->GetEdgeIndexAt(j); 771 | 772 | for (size_t k = 0; k < edgeIndex.size(); ++k) 773 | { 774 | int index = edgeIndex[k] - 1 + prevCoordCount; 775 | ss_coordIndex << to_wstring(index) << " "; 776 | //cout << " " << index << endl; 777 | } 778 | 779 | ss_coordIndex << "-1 "; 780 | } 781 | } 782 | 783 | prevCoordCount += mesh->GetCoordinateSize(); 784 | } 785 | 786 | ss_coordIndex << "'"; 787 | 788 | return CleanString(ss_coordIndex.str()); 789 | } 790 | 791 | wstring X3D_Writer::WriteNormalIndex(IShape*& iShape) const 792 | { 793 | wstringstream ss_normalIndex; 794 | ss_normalIndex << " normalIndex='"; 795 | 796 | int prevCoordCount = 0; // The number of previous coordinates 797 | 798 | for (int i = 0; i < iShape->GetMeshSize(); ++i) 799 | { 800 | Mesh* mesh = iShape->GetMeshAt(i); 801 | 802 | // Traverse triangles 803 | for (int j = 0; j < mesh->GetNormalIndexSize(); ++j) 804 | { 805 | const vector& normalIndex = mesh->GetNormalIndexAt(j); 806 | 807 | ss_normalIndex << to_wstring(normalIndex[0] - 1 + prevCoordCount) << " "; 808 | ss_normalIndex << to_wstring(normalIndex[1] - 1 + prevCoordCount) << " "; 809 | ss_normalIndex << to_wstring(normalIndex[2] - 1 + prevCoordCount) << " "; 810 | ss_normalIndex << "-1 "; 811 | } 812 | 813 | prevCoordCount += mesh->GetCoordinateSize(); 814 | } 815 | 816 | ss_normalIndex << "'"; 817 | 818 | return CleanString(ss_normalIndex.str()); 819 | } 820 | 821 | wstring X3D_Writer::WriteColor(IShape*& iShape) const 822 | { 823 | wstringstream ss_colors; 824 | 825 | bool isMultiTransparent = iShape->IsMultiTransparent(); 826 | 827 | if (isMultiTransparent) 828 | ss_colors << "GetMeshSize(); ++i) 834 | { 835 | Mesh* mesh = iShape->GetMeshAt(i); 836 | 837 | for (int j = 0; j < mesh->GetCoordinateSize(); ++j) 838 | { 839 | const Quantity_ColorRGBA& color = iShape->GetColor(mesh->GetShape()); 840 | 841 | ss_colors << NumTool::DoubleToWString(color.GetRGB().Red()) << " "; 842 | ss_colors << NumTool::DoubleToWString(color.GetRGB().Green()) << " "; 843 | ss_colors << NumTool::DoubleToWString(color.GetRGB().Blue()) << " "; 844 | 845 | if (isMultiTransparent) 846 | { 847 | double transparency = color.Alpha(); 848 | ss_colors << NumTool::DoubleToWString(transparency) << " "; 849 | } 850 | } 851 | } 852 | 853 | if (isMultiTransparent) 854 | ss_colors << "'>\n"; 855 | else 856 | ss_colors << "'>\n"; 857 | 858 | return CleanString(ss_colors.str()); 859 | } 860 | 861 | wstring X3D_Writer::WriteNormal(IShape*& iShape) const 862 | { 863 | wstringstream ss_normals; 864 | 865 | ss_normals << "\n"; 882 | 883 | return CleanString(ss_normals.str()); 884 | } 885 | 886 | const wstring X3D_Writer::Indent(int level) const 887 | { 888 | wstring indent; 889 | wstring unit = L" "; // space or tab 890 | 891 | for (int i = 0; i < level; ++i) 892 | indent += unit; 893 | 894 | return indent; 895 | } 896 | 897 | const wstring X3D_Writer::CleanString(wstring str) const 898 | { 899 | wstring from = L" '"; 900 | wstring to = L"'"; 901 | 902 | // Remove a blank at the end of '... ' string 903 | str = StrTool::ReplaceCharacter(str, from, to); 904 | 905 | return str; 906 | } 907 | 908 | bool X3D_Writer::CheckSameAppearance(const Quantity_Color& diffuseColor, bool isDiffuseOn, 909 | const Quantity_Color& emissiveColor, bool isEmissiveOn, 910 | const Quantity_Color& specularColor, bool isSpecularOn, 911 | double& shininess, bool isShininessOn, 912 | double& ambientIntensity, bool isAmbientIntensityOn, 913 | double& transparency, bool isTransparencyOn, 914 | int& appID) 915 | { 916 | // Search for the same appearance 917 | for (int i = 0; i < (int)m_appearances.size(); ++i) 918 | { 919 | Appearance app = m_appearances[i]; 920 | 921 | if (app.isDiffuseOn == isDiffuseOn 922 | && ((isDiffuseOn && app.diffuseColor.IsEqual(diffuseColor)) 923 | || !isDiffuseOn) && 924 | app.isEmissiveOn == isEmissiveOn 925 | && ((isEmissiveOn && app.emissiveColor.IsEqual(emissiveColor)) 926 | || !isEmissiveOn) && 927 | app.isSpecularOn == isSpecularOn 928 | && ((isSpecularOn && app.specularColor.IsEqual(specularColor)) 929 | || !isSpecularOn) && 930 | app.isShininessOn == isShininessOn 931 | && ((isShininessOn && abs(app.shininess - shininess) <= Precision::Confusion()) 932 | || !isShininessOn) && 933 | app.isAmbientIntensityOn == isAmbientIntensityOn 934 | && ((isAmbientIntensityOn && abs(app.ambientIntensity - ambientIntensity) <= Precision::Confusion()) 935 | || !isAmbientIntensityOn) && 936 | app.isTransparencyOn == isTransparencyOn 937 | && ((isTransparencyOn && abs(app.transparency - transparency) <= Precision::Confusion()) 938 | || !isTransparencyOn)) 939 | { 940 | appID = i; // Save the order 941 | return true; 942 | } 943 | } 944 | 945 | // Save the current appearance 946 | Appearance app; 947 | app.diffuseColor = diffuseColor; 948 | app.emissiveColor = emissiveColor; 949 | app.specularColor = specularColor; 950 | app.shininess = shininess; 951 | app.ambientIntensity = ambientIntensity; 952 | app.transparency = transparency; 953 | app.isDiffuseOn = isDiffuseOn; 954 | app.isEmissiveOn = isEmissiveOn; 955 | app.isSpecularOn = isSpecularOn; 956 | app.isShininessOn = isShininessOn; 957 | app.isAmbientIntensityOn = isAmbientIntensityOn; 958 | app.isTransparencyOn = isTransparencyOn; 959 | m_appearances.push_back(app); 960 | 961 | // Save the latest order 962 | appID = (int)m_appearances.size() - 1; 963 | 964 | return false; 965 | } 966 | 967 | wstring X3D_Writer::WriteSketchGeometry(IShape*& iShape, int level) 968 | { 969 | wstringstream ss_sg; 970 | 971 | ss_sg << Indent(level); 972 | ss_sg << "\n"; 973 | 974 | bool isMultiColored = iShape->IsMultiColored(); 975 | 976 | // Write Appearance node 977 | if (!isMultiColored) 978 | { 979 | Quantity_Color color; 980 | 981 | if (m_opt->Color()) 982 | color = iShape->GetColor().GetRGB(); 983 | else 984 | color = m_emissiveColor; 985 | 986 | ss_sg << Indent(level + 1); 987 | ss_sg << "\n"; 993 | } 994 | 995 | // Open IndexedLineSet 996 | ss_sg << Indent(level + 1); 997 | ss_sg << "\n"; 999 | 1000 | // Write coordinates 1001 | ss_sg << Indent(level + 2); 1002 | ss_sg << WriteCoordinate(iShape, false); 1003 | 1004 | // Write colors 1005 | if (isMultiColored) 1006 | { 1007 | ss_sg << Indent(level + 2); 1008 | ss_sg << WriteColor(iShape); 1009 | } 1010 | 1011 | // Close IndexedLineSet 1012 | ss_sg << Indent(level + 1); 1013 | ss_sg << "\n"; 1014 | 1015 | ss_sg << Indent(level); 1016 | ss_sg << "\n"; 1017 | 1018 | return ss_sg.str(); 1019 | } 1020 | 1021 | wstring X3D_Writer::WriteRosetteGeometry(Component*& comp, int level) 1022 | { 1023 | wstringstream ss_rg; 1024 | 1025 | if (m_opt->SFA()) // SFA-specific 1026 | { 1027 | ss_rg << "\n"; 1028 | ss_rg << Indent(level) << "\n"; 1029 | } 1030 | else 1031 | level--; 1032 | 1033 | // Write shape nodes 1034 | for (int i = 0; i < comp->GetIShapeSize(); ++i) 1035 | { 1036 | IShape* iShape = comp->GetIShapeAt(i); 1037 | 1038 | if (!iShape->IsRosette()) 1039 | continue; 1040 | 1041 | try 1042 | { 1043 | ss_rg << WriteShape(iShape, level + 1); 1044 | } 1045 | catch (...) 1046 | { 1047 | wcout << "Writing X3D has failed on Shape: " << iShape->GetName() << endl; 1048 | } 1049 | } 1050 | 1051 | if (m_opt->SFA()) // SFA-specific 1052 | { 1053 | ss_rg << Indent(level) << "\n"; 1054 | } 1055 | 1056 | return ss_rg.str(); 1057 | } 1058 | 1059 | wstring X3D_Writer::WriteSectionCapGeometry(Component*& comp, int level) 1060 | { 1061 | wstringstream ss_cg; 1062 | 1063 | int sectionCapCount = 0; 1064 | int tempID = -1; 1065 | 1066 | vector sectionCaps; 1067 | 1068 | for (int i = 0; i < comp->GetIShapeSize(); ++i) 1069 | { 1070 | IShape* iShape = comp->GetIShapeAt(i); 1071 | 1072 | if (iShape->IsSectionCap()) 1073 | sectionCaps.push_back(iShape); 1074 | } 1075 | 1076 | if (!m_opt->SFA()) 1077 | level--; 1078 | 1079 | // Write shape nodes 1080 | for (int i = 0; i < (int)sectionCaps.size(); ++i) 1081 | { 1082 | IShape* iShape = sectionCaps[i]; 1083 | 1084 | int sectionID = iShape->GetStepID(); 1085 | 1086 | if (sectionID != tempID) 1087 | { 1088 | if (m_opt->SFA()) // SFA-specific 1089 | { 1090 | ss_cg << Indent(level) << "\n"; 1093 | } 1094 | } 1095 | 1096 | try 1097 | { 1098 | ss_cg << WriteShape(iShape, level + 1); 1099 | } 1100 | catch (...) 1101 | { 1102 | wcout << "Writing X3D has failed on Shape: " << iShape->GetName() << endl; 1103 | } 1104 | 1105 | if (i == (int)sectionCaps.size() - 1 1106 | || sectionID != sectionCaps[i+1]->GetStepID()) 1107 | { 1108 | if (m_opt->SFA()) // SFA-specific 1109 | { 1110 | ss_cg << Indent(level) << "\n"; 1111 | } 1112 | } 1113 | 1114 | tempID = sectionID; 1115 | } 1116 | 1117 | return ss_cg.str(); 1118 | } 1119 | 1120 | void X3D_Writer::CountIndent(int level) 1121 | { 1122 | // Used for counting indent of 'Transform' and 'Group' nodes 1123 | if (m_indentCountMap.find(level) == m_indentCountMap.end()) 1124 | m_indentCountMap.insert({ level, 1 }); 1125 | else 1126 | { 1127 | int count = m_indentCountMap[level]; 1128 | count++; 1129 | m_indentCountMap[level] = count; 1130 | } 1131 | } 1132 | 1133 | void X3D_Writer::PrintIndentCount(void) 1134 | { 1135 | printf("Indent Count\n"); 1136 | 1137 | for (map::iterator it = m_indentCountMap.begin(); it != m_indentCountMap.end(); ++it) 1138 | printf("indent %d - %d\n", it->first, it->second); 1139 | } 1140 | 1141 | void X3D_Writer::PrintMaterialCount(void) const 1142 | { 1143 | printf("Number of Materials: %d\n", (int)m_appearances.size()); 1144 | } 1145 | 1146 | wstring X3D_Writer::WriteGDT(Model*& model, int level) 1147 | { 1148 | wstringstream ss_gdt; 1149 | 1150 | ss_gdt << Indent(level); 1151 | ss_gdt << "SFA()) 1154 | ss_gdt << " id='highlight'"; 1155 | 1156 | ss_gdt << " DEF='GD&T'>\n"; 1157 | 1158 | for (int i = 0; i < model->GetGDTSize(); ++i) 1159 | { 1160 | GDT_Item* gdt = model->GetGDTAt(i); 1161 | 1162 | ss_gdt << Indent(level + 1); 1163 | ss_gdt << "SFA()) 1166 | ss_gdt << " id='" << gdt->GetName().c_str() << "'"; 1167 | 1168 | ss_gdt << " DEF='" << gdt->GetName().c_str() << "'"; 1169 | ss_gdt << ">\n"; 1170 | 1171 | TopoDS_Shape shape; 1172 | IShape* faceShape = new IShape(shape); 1173 | IShape* edgeShape = new IShape(shape); 1174 | 1175 | for (int j = 0; j < gdt->GetMeshSize(); ++j) 1176 | { 1177 | Mesh* mesh = gdt->GetMeshAt(j); 1178 | 1179 | if (mesh->GetFaceIndexSize() > 0) 1180 | faceShape->AddMesh(mesh); 1181 | else 1182 | edgeShape->AddMesh(mesh); 1183 | } 1184 | 1185 | // face shape 1186 | if (faceShape->GetMeshSize() > 0) 1187 | { 1188 | ss_gdt << Indent(level + 2); 1189 | ss_gdt << "\n"; 1190 | 1191 | // Write Appearance node 1192 | ss_gdt << Indent(level + 3); 1193 | 1194 | ss_gdt << WriteAppearance(faceShape, m_gdtColor, true, 1195 | m_emissiveColor, false, 1196 | m_specularColor, true, 1197 | m_shininess, true, 1198 | m_ambientIntensity, false, 1199 | m_transparency, false); 1200 | 1201 | ss_gdt << Indent(level + 3); 1202 | 1203 | ss_gdt << "Normal()) 1206 | ss_gdt << " creaseAngle='" << NumTool::DoubleToWString(m_creaseAngle) << "'"; 1207 | 1208 | ss_gdt << " solid='false'"; 1209 | 1210 | ss_gdt << WriteCoordinateIndex(faceShape, true); 1211 | 1212 | if (m_opt->Normal()) 1213 | ss_gdt << WriteNormalIndex(faceShape); 1214 | 1215 | ss_gdt << ">\n"; 1216 | 1217 | // Write coordinates 1218 | ss_gdt << Indent(level + 4); 1219 | ss_gdt << WriteCoordinate(faceShape, false); 1220 | 1221 | // Close IndexedFaceSet 1222 | ss_gdt << Indent(level + 3); 1223 | ss_gdt << "\n"; 1224 | 1225 | ss_gdt << Indent(level + 2); 1226 | ss_gdt << "\n"; 1227 | } 1228 | 1229 | // edge shape 1230 | if (edgeShape->GetMeshSize() > 0) 1231 | { 1232 | ss_gdt << Indent(level + 2); 1233 | ss_gdt << "\n"; 1234 | 1235 | // Write Appearance node 1236 | ss_gdt << Indent(level + 3); 1237 | 1238 | ss_gdt << WriteAppearance(edgeShape, m_gdtColor, false, 1239 | m_gdtColor2, true, 1240 | m_specularColor, false, 1241 | m_shininess, false, 1242 | m_ambientIntensity, false, 1243 | m_transparency, false); 1244 | 1245 | ss_gdt << Indent(level + 3); 1246 | ss_gdt << "\n"; 1251 | 1252 | // Write coordinates 1253 | ss_gdt << Indent(level + 4); 1254 | ss_gdt << WriteCoordinate(edgeShape, false); 1255 | 1256 | // Close IndexedFaceSet 1257 | ss_gdt << Indent(level + 3); 1258 | ss_gdt << "\n"; 1259 | 1260 | ss_gdt << Indent(level + 2); 1261 | ss_gdt << "\n"; 1262 | } 1263 | 1264 | ss_gdt << Indent(level + 1); 1265 | ss_gdt << "\n"; 1266 | } 1267 | 1268 | ss_gdt << Indent(level); 1269 | ss_gdt << "\n"; 1270 | 1271 | return ss_gdt.str(); 1272 | } 1273 | 1274 | void X3D_Writer::Clear(void) 1275 | { 1276 | m_appearances.clear(); 1277 | m_indentCountMap.clear(); 1278 | } 1279 | -------------------------------------------------------------------------------- /STP2X3D/X3D_Writer.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | class Component; 4 | class IShape; 5 | 6 | struct Appearance 7 | { 8 | Quantity_Color diffuseColor; 9 | Quantity_Color specularColor; 10 | Quantity_Color emissiveColor; 11 | double shininess = 0.0; 12 | double ambientIntensity = 0.0; 13 | double transparency = 0.0; 14 | 15 | bool isDiffuseOn = false; 16 | bool isEmissiveOn = false; 17 | bool isSpecularOn = false; 18 | bool isShininessOn = false; 19 | bool isAmbientIntensityOn = false; 20 | bool isTransparencyOn = false; 21 | }; 22 | 23 | class X3D_Writer 24 | { 25 | public: 26 | X3D_Writer(S2X_Option* opt); 27 | ~X3D_Writer(void); 28 | 29 | void WriteX3D(Model*& model); 30 | 31 | protected: 32 | wstring OpenHeader(void) const; 33 | wstring CloseHeader(void) const; 34 | 35 | wstring WriteViewpoint(Model*& model, int level) const; 36 | 37 | wstring WriteModel(Model*& model, int level); 38 | wstring WriteComponent(Component*& comp, int level); 39 | 40 | wstring WriteTransformAttributes(const gp_Trsf& trsf) const; 41 | wstring WriteShape(IShape*& iShape, int level); 42 | wstring WriteIndexedFaceSet(IShape*& iShape, int level); 43 | wstring WriteIndexedLineSet(IShape*& iShape, int level); 44 | 45 | wstring WriteAppearance(IShape*& iShape, const Quantity_Color& diffuseColor, bool isDiffuseOn, 46 | const Quantity_Color& emissiveColor, bool isEmissiveOn, 47 | const Quantity_Color& specularColor, bool isSpecularOn, 48 | double& shininess, bool isShininessOn, 49 | double& ambientIntensity, bool isAmbientIntensityOn, 50 | double& transparency, bool isTransparencyOn); 51 | wstring WriteCoordinate(IShape*& iShape, bool isBoundaryEdges) const; 52 | wstring WriteCoordinateIndex(IShape*& iShape, bool faceMesh) const; 53 | wstring WriteNormalIndex(IShape*& iShape) const; 54 | wstring WriteColor(IShape*& iShape) const; 55 | wstring WriteNormal(IShape*& iShape) const; 56 | 57 | const wstring Indent(int level) const; 58 | const wstring CleanString(wstring str) const; 59 | 60 | bool CheckSameAppearance(const Quantity_Color& diffuseColor, bool isDiffuseOn, 61 | const Quantity_Color& emissiveColor, bool isEmissiveOn, 62 | const Quantity_Color& specularColor, bool isSpecularOn, 63 | double& shininess, bool isShininessOn, 64 | double& ambientIntensity, bool isAmbientIntensityOn, 65 | double& transparency, bool isTransparencyOn, 66 | int& appID); 67 | void Clear(void); 68 | 69 | // SFA-specific functions 70 | wstring WriteSketchGeometry(IShape*& iShape, int level); 71 | wstring WriteRosetteGeometry(Component*& comp, int level); 72 | wstring WriteSectionCapGeometry(Component*& comp, int level); 73 | void CountIndent(int level); 74 | void PrintIndentCount(void); 75 | void PrintMaterialCount(void) const; 76 | 77 | wstring WriteGDT(Model*& model, int level); 78 | 79 | private: 80 | S2X_Option* m_opt; 81 | 82 | Quantity_Color m_diffuseColor; 83 | Quantity_Color m_emissiveColor; 84 | Quantity_Color m_specularColor; 85 | Quantity_Color m_gdtColor, m_gdtColor2; 86 | 87 | double m_shininess; 88 | double m_ambientIntensity; 89 | double m_transparency; 90 | 91 | double m_creaseAngle; 92 | 93 | vector m_appearances; 94 | 95 | // SFA-specific variables 96 | map m_indentCountMap; 97 | }; -------------------------------------------------------------------------------- /STP2X3D/stdafx.cpp: -------------------------------------------------------------------------------- 1 | // stdafx.cpp : source file that includes just the standard includes 2 | // STP2X3D.pch will be the pre-compiled header 3 | // stdafx.obj will contain the pre-compiled type information 4 | 5 | #include "stdafx.h" 6 | 7 | // TODO: reference any additional headers you need in STDAFX.H 8 | // and not in this file 9 | -------------------------------------------------------------------------------- /STP2X3D/stdafx.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include 4 | using namespace std; 5 | 6 | #include 7 | #include 8 | #include 9 | #include 10 | #include 11 | #include 12 | #include 13 | #include 14 | #include 15 | 16 | #include "OCCLib.h" 17 | #include "OCCUtil.h" 18 | #include "StopWatch.h" 19 | #include "NumTool.h" 20 | #include "StrTool.h" 21 | #include "S2X_Option.h" 22 | #include "ShapeType.h" 23 | #include "Model.h" 24 | 25 | constexpr auto PI = 3.14159265359; 26 | 27 | -------------------------------------------------------------------------------- /USAGE.md: -------------------------------------------------------------------------------- 1 | # Usage Guide 2 | The following information describes how to use the software. Running the execution file in the command line prompt will also give you the instruction. 3 | 4 | ## How to use in the command line prompt 5 | - STP2X3D.exe option1 value1 option2 value2 .. 6 | 7 | ## Options 8 | - --input Input STEP file path 9 | - --normal Normal vector (1:yes, 0:no) default=0 10 | - --color Color (1:yes, 0:no) default=1 11 | - --edge Boundary edges (1:yes, 0:no) default=0 12 | - --sketch Sketch geometry (1:yes, 0:no) default=1 13 | - --html Output file type (1:html, 0:x3d) default=0 14 | - --quality Mesh quality (1-low to 10-high) default=5 15 | - --gdt Geometric elements related to GD&T (1:yes, 0:no) default=0 16 | - --tess Adaptive tessellation per each body (1:yes, 0:no) default=0 17 | - --rosette Rosette used for Composite Design (1:yes, 0:no) default=0 18 | - --cap Cap geometries for sections (1:yes, 0:no) default=0 19 | - --tsolid Tessellated solids (1:yes, 0:no) default=1 20 | - --batch Processing multiple STEP files (1:include sub-directories, 0:current dir). Followed by a folder path (e.g. --batch 0 c:\\) 21 | 22 | ## Examples 23 | - STP2X3D.exe --input Model.stp --edge 1 --quality 7 24 | - STP2X3D.exe --html 1 --sketch 0 --input Model.step 25 | - STP2X3D.exe --color 0 --batch 1 C:\Folder --normal 1 26 | --------------------------------------------------------------------------------