/**************************************************************************** ** Copyright (c) 2021, Fougue Ltd. ** All rights reserved. ** See license at https://github.com/fougue/mayo/blob/master/LICENSE.txt ****************************************************************************/ #include "io_occ_step.h" #include "io_occ_caf.h" #include "../base/messenger.h" #include "../base/meta_enum.h" #include "../base/occ_handle.h" #include "../base/occ_static_variables_rollback.h" #include "../base/property_builtins.h" #include "../base/property_enumeration.h" #include "../base/string_conv.h" #include "../base/task_progress.h" #include "../base/tkernel_utils.h" #include "../base/enumeration_fromenum.h" #include #include #include #include #include #include namespace Mayo { namespace IO { class OccStepReader::Properties : public PropertyGroup { MAYO_DECLARE_TEXT_ID_FUNCTIONS(Mayo::IO::OccStepReader::Properties) public: Properties(PropertyGroup* parentGroup) : PropertyGroup(parentGroup) { this->productContext.setDescription( textIdTr("When reading AP 209 STEP files, allows selecting either only `design` " "or `analysis`, or both types of products for translation\n" "Note that in AP 203 and AP214 files all products should be marked as " "`design`, so if this mode is set to `analysis`, nothing will be read")); this->assemblyLevel.setDescription( textIdTr("Specifies which data should be read for the products found in the STEP file")); this->preferredShapeRepresentation.setDescription( textIdTr("Specifies preferred type of representation of the shape of the product, in " "case if a STEP file contains more than one representation (i.e. multiple " "`PRODUCT_DEFINITION_SHAPE` entities) for a single product")); this->readShapeAspect.setDescription( textIdTr("Defines whether shapes associated with the `PRODUCT_DEFINITION_SHAPE` entity " "of the product via `SHAPE_ASPECT` should be translated.\n" "This kind of association was used for the representation of hybrid models (i.e. models " "whose shape is composed of different types of representations) in AP 203 files " "before 1998, but it is also used to associate auxiliary information with the " "sub-shapes of the part. Though STEP translator tries to recognize such cases " "correctly, this parameter may be useful to avoid unconditionally translation " "of shapes associated via `SHAPE_ASPECT` entities.")); this->readSubShapesNames.setDescription( textIdTr("Indicates whether to read sub-shape names from 'Name' attributes of " "STEP Representation Items")); this->productContext.setDescriptions({ { ProductContext::Design, textIdTr("Translate only products that have " "`PRODUCT_DEFINITION_CONTEXT` with field `life_cycle_stage` set to `design`") }, { ProductContext::Analysis, textIdTr("Translate only products that have " "`PRODUCT_DEFINITION_CONTEXT` with field `life_cycle_stage` set to `analysis`") }, { ProductContext::Both, textIdTr("Translates all products") } }); this->assemblyLevel.setDescriptions({ { AssemblyLevel::Assembly, textIdTr("Translate the assembly structure and shapes " "associated with parts only(not with sub-assemblies)") }, { AssemblyLevel::Structure, textIdTr("Translate only the assembly structure " "without shapes(a structure of empty compounds). This mode can be useful as " "an intermediate step in applications requiring specialized processing of assembly parts") }, { AssemblyLevel::Shape, textIdTr("Translate only shapes associated with the " "product, ignoring the assembly structure (if any). This can be useful to " "translate only a shape associated with specific product, as a complement to assembly mode") }, { AssemblyLevel::All, textIdTr("Translate both the assembly structure and all " "associated shapes. If both shape and sub-assemblies are associated with the " "same product, all of them are read and put in a single compound") } }); this->preferredShapeRepresentation.addDescription( ShapeRepresentation::All, textIdTr("Translate all representations(if more than one, put in compound)")); this->encoding.setDescriptions({ { Encoding::Shift_JIS, textIdTr("Shift Japanese Industrial Standards") }, { Encoding::EUC, textIdTr("EUC(Extended Unix Code), multi-byte encoding primarily " "for Japanese, Korean, and simplified Chinese") }, { Encoding::GB, textIdTr("GB(Guobiao) encoding for Simplified Chinese") } }); } void restoreDefaults() override { const OccStepReader::Parameters params; this->productContext.setValue(params.productContext); this->assemblyLevel.setValue(params.assemblyLevel); this->preferredShapeRepresentation.setValue(params.preferredShapeRepresentation); this->readShapeAspect.setValue(params.readShapeAspect); this->readSubShapesNames.setValue(params.readSubShapesNames); this->encoding.setValue(params.encoding); } PropertyEnum productContext{ this, textId("productContext") }; PropertyEnum assemblyLevel{ this, textId("assemblyLevel") }; PropertyEnum preferredShapeRepresentation{ this, textId("preferredShapeRepresentation") }; PropertyBool readShapeAspect{ this, textId("readShapeAspect") }; PropertyBool readSubShapesNames{ this, textId("readSubShapesNames") }; PropertyEnum encoding{ this, textId("encoding") }; }; OccStepReader::OccStepReader() { MayoIO_CafGlobalScopedLock(cafLock); m_reader = new(&m_readerStorage) STEPCAFControl_Reader(); STEPCAFControl_Controller::Init(); m_reader->SetColorMode(true); m_reader->SetNameMode(true); m_reader->SetLayerMode(true); m_reader->SetPropsMode(true); m_reader->SetGDTMode(true); m_reader->SetMatMode(true); m_reader->SetViewMode(true); } OccStepReader::~OccStepReader() { m_reader->~STEPCAFControl_Reader(); } bool OccStepReader::readFile(const FilePath& filepath, TaskProgress* progress) { MayoIO_CafGlobalScopedLock(cafLock); OccStaticVariablesRollback rollback; this->changeStaticVariables(&rollback); return Private::cafReadFile(*m_reader, filepath, progress); } TDF_LabelSequence OccStepReader::transfer(DocumentPtr doc, TaskProgress* progress) { MayoIO_CafGlobalScopedLock(cafLock); OccStaticVariablesRollback rollback; this->changeStaticVariables(&rollback); return Private::cafTransfer(*m_reader, doc, progress); } std::unique_ptr OccStepReader::createProperties(PropertyGroup* parentGroup) { return std::make_unique(parentGroup); } void OccStepReader::applyProperties(const PropertyGroup* group) { auto ptr = dynamic_cast(group); if (ptr) { m_params.productContext = ptr->productContext; m_params.assemblyLevel = ptr->assemblyLevel; m_params.preferredShapeRepresentation = ptr->preferredShapeRepresentation; m_params.readShapeAspect = ptr->readShapeAspect; m_params.readSubShapesNames = ptr->readSubShapesNames; m_params.encoding = ptr->encoding; } } void OccStepReader::changeStaticVariables(OccStaticVariablesRollback* rollback) const { auto fnOccEncoding = [](Encoding code) { switch (code) { case Encoding::Shift_JIS: return "SJIS"; case Encoding::EUC: return "EUC"; case Encoding::ANSI: return "ANSI"; case Encoding::GB: return "GB"; case Encoding::UTF8: return "UTF8"; #if OCC_VERSION_HEX >= OCC_VERSION_CHECK(7, 5, 0) // Windows-native ("ANSI") 8-bit code pages case Encoding::CP_1250: return "CP1250"; case Encoding::CP_1251: return "CP1251"; case Encoding::CP_1252: return "CP1252"; case Encoding::CP_1253: return "CP1253"; case Encoding::CP_1254: return "CP1254"; case Encoding::CP_1255: return "CP1255"; case Encoding::CP_1256: return "CP1256"; case Encoding::CP_1257: return "CP1257"; case Encoding::CP_1258: return "CP1258"; // ISO8859 8-bit code pages case Encoding::ISO_8859_1: return "iso8859-1"; case Encoding::ISO_8859_2: return "iso8859-2"; case Encoding::ISO_8859_3: return "iso8859-3"; case Encoding::ISO_8859_4: return "iso8859-4"; case Encoding::ISO_8859_5: return "iso8859-5"; case Encoding::ISO_8859_6: return "iso8859-6"; case Encoding::ISO_8859_7: return "iso8859-7"; case Encoding::ISO_8859_8: return "iso8859-8"; case Encoding::ISO_8859_9: return "iso8859-9"; #endif } throw std::invalid_argument(fmt::format("{} isn't supported", MetaEnum::name(code))); }; const char strKeyReadStepCodePage[] = #if OCC_VERSION_HEX >= OCC_VERSION_CHECK(7, 5, 0) "read.step.codepage"; #else "read.stepcaf.codepage"; #endif rollback->change("read.step.product.context", int(m_params.productContext)); rollback->change("read.step.assembly.level", int(m_params.assemblyLevel)); rollback->change("read.step.shape.repr", int(m_params.preferredShapeRepresentation)); rollback->change("read.step.shape.aspect", int(m_params.readShapeAspect ? 1 : 0)); rollback->change("read.stepcaf.subshapes.name", int(m_params.readSubShapesNames ? 1 : 0)); rollback->change(strKeyReadStepCodePage, fnOccEncoding(m_params.encoding)); } class OccStepWriter::Properties : public PropertyGroup { MAYO_DECLARE_TEXT_ID_FUNCTIONS(Mayo::IO::OccStepWriter::Properties) public: Properties(PropertyGroup* parentGroup) : PropertyGroup(parentGroup) { this->schema.setDescription(textIdTr("Version of schema used for the output STEP file")); this->lengthUnit.setDescription( textIdTr("Defines a unit in which the STEP file should be written. If set to " "unit other than millimeter, the model is converted to these units " "during the translation") ); this->freeVertexMode.setDescription( textIdTr("Parameter to write all free vertices in one SDR (name and style of " "vertex are lost) or each vertex in its own SDR (name and style of " "vertex are exported)") ); this->freeVertexMode.setDescriptions({ { FreeVertexMode::Compound, textIdTr("All free vertices are united into one " "compound and exported in one shape definition representation (vertex name " "and style are lost)") }, { FreeVertexMode::Single, textIdTr("Each vertex is exported in its own " "`SHAPE DEFINITION REPRESENTATION`(vertex name and style are not lost, but " "the STEP file size increases)") }, }); this->writePCurves.setDescription( textIdTr("Indicates whether parametric curves (curves in parametric space of surface) should be " "written into the STEP file.\n" "It can be disabled in order to minimize the size of the resulting file.") ); this->writeSubShapesNames.setDescription( textIdTr("Indicates whether to write sub-shape names to 'Name' attributes of " "STEP Representation Items") ); this->headerAuthor.setDescription(textIdTr("Author attribute in STEP header")); this->headerOrganization.setDescription(textIdTr("Organization(of author) attribute in STEP header")); this->headerOriginatingSystem.setDescription(textIdTr("Originating system attribute in STEP header")); this->headerDescription.setDescription(textIdTr("Description attribute in STEP header")); } void restoreDefaults() override { const OccStepWriter::Parameters params; this->schema.setValue(params.schema); this->lengthUnit.setValue(params.lengthUnit); this->assemblyMode.setValue(params.assemblyMode); this->freeVertexMode.setValue(params.freeVertexMode); this->writePCurves.setValue(params.writeParametricCurves); this->writeSubShapesNames.setValue(params.writeSubShapesNames); this->headerAuthor.setValue({}); this->headerOrganization.setValue({}); this->headerOriginatingSystem.setValue(XSTEP_SYSTEM_VERSION); this->headerDescription.setValue("OpenCascade Model"); } PropertyEnum schema{ this, textId("schema") }; PropertyEnum lengthUnit{ this, textId("lengthUnit") }; PropertyEnum assemblyMode{ this, textId("assemblyMode") }; PropertyEnum freeVertexMode{ this, textId("freeVertexMode") }; PropertyBool writePCurves{ this, textId("writeParametericCurves") }; PropertyBool writeSubShapesNames{ this, textId("writeSubShapesNames") }; PropertyString headerAuthor{ this, textId("headerAuthor") }; PropertyString headerOrganization{ this, textId("headerOrganization") }; PropertyString headerOriginatingSystem{ this, textId("headerOriginatingSystem") }; PropertyString headerDescription{ this, textId("headerDescription") }; }; OccStepWriter::OccStepWriter() { MayoIO_CafGlobalScopedLock(cafLock); m_writer = new(&m_writerStorage) STEPCAFControl_Writer(); STEPCAFControl_Controller::Init(); m_writer->SetColorMode(true); m_writer->SetNameMode(true); m_writer->SetLayerMode(true); m_writer->SetPropsMode(true); m_writer->SetDimTolMode(true); m_writer->SetMaterialMode(true); } OccStepWriter::~OccStepWriter() { m_writer->~STEPCAFControl_Writer(); } bool OccStepWriter::transfer(Span appItems, TaskProgress* progress) { MayoIO_CafGlobalScopedLock(cafLock); OccStaticVariablesRollback rollback; this->changeStaticVariables(&rollback); if (m_params.schema != m_schemaLastTransfer) { // NOTE from $OCC_7.4.0_DIR/doc/pdf/user_guides/occt_step.pdf (page 26) // For the parameter "write.step.schema" to take effect, method STEPControl_Writer::Model(true) // should be called after changing this parameter (corresponding command in DRAW is "newmodel") m_writer->ChangeWriter().Model(true); m_schemaLastTransfer = m_params.schema; } return Private::cafTransfer(*m_writer, appItems, progress); } bool OccStepWriter::writeFile(const FilePath& filepath, TaskProgress* /*progress*/) { MayoIO_CafGlobalScopedLock(cafLock); OccStaticVariablesRollback rollback; this->changeStaticVariables(&rollback); APIHeaderSection_MakeHeader makeHeader(m_writer->ChangeWriter().Model()); makeHeader.SetAuthorValue(1, to_OccHandleHAsciiString(m_params.headerAuthor)); makeHeader.SetOrganizationValue(1, to_OccHandleHAsciiString(m_params.headerOrganization)); makeHeader.SetOriginatingSystem(to_OccHandleHAsciiString(m_params.headerOriginatingSystem)); makeHeader.SetDescriptionValue(1, to_OccHandleHAsciiString(m_params.headerDescription)); const IFSelect_ReturnStatus err = m_writer->Write(filepath.u8string().c_str()); return err == IFSelect_RetDone; } std::unique_ptr OccStepWriter::createProperties(PropertyGroup* parentGroup) { return std::make_unique(parentGroup); } void OccStepWriter::applyProperties(const PropertyGroup* group) { auto ptr = dynamic_cast(group); if (ptr) { m_params.schema = ptr->schema; m_params.lengthUnit = ptr->lengthUnit; m_params.assemblyMode = ptr->assemblyMode; m_params.freeVertexMode = ptr->freeVertexMode; m_params.writeParametricCurves = ptr->writePCurves; m_params.writeSubShapesNames = ptr->writeSubShapesNames; m_params.headerAuthor = ptr->headerAuthor; m_params.headerOrganization = ptr->headerOrganization; m_params.headerOriginatingSystem = ptr->headerOriginatingSystem; m_params.headerDescription = ptr->headerDescription; } } void OccStepWriter::changeStaticVariables(OccStaticVariablesRollback* rollback) { rollback->change("write.step.schema", int(m_params.schema)); rollback->change("write.step.unit", OccCommon::toCafString(m_params.lengthUnit)); rollback->change("write.step.assembly", int(m_params.assemblyMode)); rollback->change("write.step.vertex.mode", int(m_params.freeVertexMode)); rollback->change("write.surfacecurve.mode", int(m_params.writeParametricCurves ? 1 : 0)); rollback->change("write.stepcaf.subshapes.name", int(m_params.writeSubShapesNames ? 1 : 0)); } } // namespace IO } // namespace Mayo