/////////////////////////////////////////////////////////////////////////////// // Copyright (C) 2002-2025, Open Design Alliance (the "Alliance"). // All rights reserved. // // This software and its documentation and related materials are owned by // the Alliance. The software may only be incorporated into application // programs owned by members of the Alliance, subject to a signed // Membership Agreement and Supplemental Software License Agreement with the // Alliance. The structure and organization of this software are the valuable // trade secrets of the Alliance and its suppliers. The software is also // protected by copyright law and international treaty provisions. Application // programs incorporating this software must include the following statement // with their copyright notices: // // This application incorporates Open Design Alliance software pursuant to a license // agreement with Open Design Alliance. // Open Design Alliance Copyright (C) 2002-2025 by Open Design Alliance. // All rights reserved. // // By use of this software, its documentation or related materials, you // acknowledge and accept the above terms. /////////////////////////////////////////////////////////////////////////////// #ifndef OD_TV_PRC2VISUALIZEGEOMCOLLECTOR_H #define OD_TV_PRC2VISUALIZEGEOMCOLLECTOR_H /** \remarks This code was created on the base of the code from the ExVisualizeDevice module */ // ODA Visualize #include "TvDatabase.h" #include "TvEntity.h" // ODA PRC #include "GiGs/PrcGiContext.h" // ODA Platform #include "Gi/GiDummyGeometry.h" #include "Gi/GiLinetypeRedir.h" #include "Gi/GiTextStyle.h" #include "Gi/GiDrawImpl.h" #include "Ge/GeCircArc3d.h" #include "Ge/GeNurbCurve3d.h" #include "Gs/GsDbRootLinkage.h" #include "OdPerfTimer.h" #include "DbBaseHostAppServices.h" #include class OdGiMaterialTraitsTaker; template inline void hash_combine(std::size_t& seed, const T& val) { seed ^= std::hash{}(val) + 0x9e3779b9 + (seed << 6) + (seed >> 2); } struct SubGroupTraitsData { OdUInt32 m_nColor; double m_dTransparency; OdUInt64 m_linetypeHandle; OdUInt64 m_materialHandle; OdTvMatrix m_mtx; SubGroupTraitsData() : m_nColor(0), m_dTransparency(0.), m_linetypeHandle(0.), m_materialHandle(0.) { } bool operator==(const SubGroupTraitsData& other) const { return m_nColor == other.m_nColor && m_dTransparency == other.m_dTransparency && m_linetypeHandle == other.m_linetypeHandle && m_materialHandle == other.m_materialHandle && m_mtx == other.m_mtx; } }; struct GenericMaterialData { OdUInt8 m_nAmbientMethod; OdUInt32 m_nAmbientColor; OdUInt8 m_nDiffuseMethod; OdUInt32 m_nDiffuseColor; OdUInt8 m_nEmisisonMethod; OdUInt32 m_nEmisionColor; OdUInt8 m_nSpecularMethod; OdUInt32 m_nSpecularColor; double m_dGlossFactor; GenericMaterialData() : m_nAmbientMethod(0), m_nAmbientColor(0), m_nDiffuseMethod(0), m_nDiffuseColor(0), m_nEmisisonMethod(0), m_nEmisionColor(0) , m_nSpecularMethod(0), m_nSpecularColor(0), m_dGlossFactor(0.) { } bool operator<(const GenericMaterialData& other) const { if (m_nAmbientMethod != other.m_nAmbientMethod) return m_nAmbientMethod < other.m_nAmbientMethod; if (m_nAmbientColor != other.m_nAmbientColor) return m_nAmbientColor < other.m_nAmbientColor; if (m_nDiffuseMethod != other.m_nDiffuseMethod) return m_nDiffuseMethod < other.m_nDiffuseMethod; if (m_nDiffuseColor != other.m_nDiffuseColor) return m_nDiffuseColor < other.m_nDiffuseColor; if (m_nEmisisonMethod != other.m_nEmisisonMethod) return m_nEmisisonMethod < other.m_nEmisisonMethod; if (m_nEmisionColor != other.m_nEmisionColor) return m_nEmisionColor < other.m_nEmisionColor; if (m_nSpecularMethod != other.m_nSpecularMethod) return m_nSpecularMethod < other.m_nSpecularMethod; if (m_nSpecularColor != other.m_nSpecularColor) return m_nSpecularColor < other.m_nSpecularColor; if (!OdEqual(m_dGlossFactor, other.m_dGlossFactor, 1.e-4)) return m_dGlossFactor < other.m_dGlossFactor; return false; } }; // Hash function for OdTvMatrix namespace std { template <> struct hash { std::size_t operator()(const SubGroupTraitsData& data) const { std::size_t seed = 0; // Combine the hashes of each member hash_combine(seed, data.m_nColor); hash_combine(seed, data.m_dTransparency); hash_combine(seed, data.m_linetypeHandle); hash_combine(seed, data.m_materialHandle); hash_combine(seed, data.m_mtx); // Using the custom hash for OdTvMatrix return seed; } }; template <> struct hash { std::size_t operator()(const OdTvMatrix& matrix) const { std::size_t seed = 0; // Combine the hash of each element in the matrix for (int i = 0; i < 4; ++i) { for (int j = 0; j < 4; ++j) { hash_combine(seed, matrix[i][j]); } } return seed; } }; template <> struct hash { std::size_t operator()(const GenericMaterialData& data) const { std::size_t seed = 0; // Combine the hashes of each member hash_combine(seed, data.m_nAmbientMethod); hash_combine(seed, data.m_nAmbientColor); hash_combine(seed, data.m_nDiffuseMethod); hash_combine(seed, data.m_nDiffuseMethod); hash_combine(seed, data.m_nEmisisonMethod); hash_combine(seed, data.m_nEmisionColor); hash_combine(seed, data.m_nSpecularMethod); hash_combine(seed, data.m_nSpecularColor); hash_combine(seed, data.m_dGlossFactor); // Using the custom hash for OdTvMatrix return seed; } }; } /** \details It is a dummy implementation of the viewport draw. This class is used as the base for the PRC geometry collector */ class OdGiViewportDraw_DummyEx : public OdGiDummyViewportDraw< OdGiViewportDraw >, public OdGiDummyViewportGeometry< OdGiViewportGeometry > { public: /** \details Constructor for the OdGiViewportDraw_Dummy class. Creates an object with the associated database specified by the pDb parameter. \param pDb [in] Pointer to a database. */ OdGiViewportDraw_DummyEx() { } /** \details Retrieves raw geometry associated with this object. \returns raw geometry. */ virtual OdGiGeometry& rawGeometry() const { return *static_cast(const_cast(this)); } /** \details Retrieves a viewport geometry associated with this object. \returns reference to a viewport geometry as OdGiViewportGeometry instance. */ virtual OdGiViewportGeometry& geometry() const { return *static_cast(const_cast(this)); } /** \details Adds reference to this object. Currently not implemented. */ void addRef() { } /** \details Releases reference to this object. Currently not implemented. */ void release() ODRX_NOEXCEPT { } }; /** \details Object for storing text style cache data */ struct OdTvVisualize2PrcTextStyleCacheData { OdString m_name; OdString m_typeface; OdString m_fileName; int m_charset; int m_family; OdUInt8 m_flags; //1 = italic, 2 = bold double m_dObliquingAngle; OdTvVisualize2PrcTextStyleCacheData() : m_name(L""), m_typeface(L""), m_fileName(L""), m_charset(0), m_family(0), m_flags(0), m_dObliquingAngle(0) { }; void setItalic(bool bSet) { SETBIT(m_flags, 1, bSet); } void setBold(bool bSet) { SETBIT(m_flags, 2, bSet); } bool operator< (const OdTvVisualize2PrcTextStyleCacheData& data) const { if (m_name < data.m_name) return true; if (m_name > data.m_name) return false; if (m_typeface < data.m_typeface) return true; if (m_typeface > data.m_typeface) return false; if (m_fileName < data.m_fileName) return true; if (m_fileName > data.m_fileName) return false; if (m_charset < data.m_charset) return true; if (m_charset > data.m_charset) return false; if (m_family < data.m_family) return true; if (m_family > data.m_family) return false; if (m_flags < data.m_flags) return true; if (m_flags > data.m_flags) return false; if (m_dObliquingAngle < data.m_dObliquingAngle) return true; if (m_dObliquingAngle > data.m_dObliquingAngle) return false; return false; } }; /** \details Additional types */ typedef OdStack OdTvMatrix3dStack; typedef std::map< OdDbStub*, OdTvLinetypeId > OdTvStubToLinetypeMap; typedef std::map< OdPrcObjectId, OdTvMaterialId > OdTvPrcIdToMaterialMap; typedef std::map< OdString, OdTvRasterImageId > OdTvStringToRasterImageMap; typedef std::map< OdTvVisualize2PrcTextStyleCacheData, OdTvTextStyleId > OdTvTextStyleCacheToTextStyleMap; typedef std::map< OdDbStub*, OdString > OdTvStubToNamesMap; /** \details This object contains state information with visualize object Id (entity of subgroup) */ struct OdTvVisualize2TvObjectId { OdTvEntityId m_entId; OdTvGeometryDataId m_subGroupId; OdTvVisualize2TvObjectId() { m_entId.setNull(); m_subGroupId.setNull(); } void reset() { m_entId.setNull(); m_subGroupId.setNull(); } bool exist() const { if (!m_entId.isNull()) return true; if (!m_subGroupId.isNull()) return true; return false; } }; /** \details This object contains state information for the subgroups parent's stack */ struct OdTvVisualize2PrcParentsOfSubGroupDef { OdGiSubEntityTraitsData traits; OdTvVisualize2TvObjectId parentObjectId; OdTvGeometryDataId subGroupId; bool bTraitsValid; bool bDueToTransform; OdTvVisualize2PrcParentsOfSubGroupDef(OdTvGeometryDataId id, bool bTraisValid, const OdGiSubEntityTraitsData& data, bool bBecauseOfTransform, OdTvVisualize2TvObjectId parentId) { subGroupId = id; bTraitsValid = bTraisValid; traits = data; bDueToTransform = bBecauseOfTransform; parentObjectId = parentId; } OdTvVisualize2PrcParentsOfSubGroupDef() :bTraitsValid(false) ,bDueToTransform(false) { } }; typedef OdStack< OdTvVisualize2PrcParentsOfSubGroupDef > OdTvVisualize2PrcParentsOfSubGroupStack; /** \details This object is a wrapper over the timer with safety from nested starts */ class OdTvVisualize2PrcTimer { public: OdTvVisualize2PrcTimer(OdPerfTimerBase* pTimer); ~OdTvVisualize2PrcTimer(); void start(); void stop(); void reset(); double time() const; protected: OdPerfTimerBase* m_pTimer; double m_dElapsed; OdUInt32 m_nStarts; }; /** \details This class is used to ensure OdTvVisualizePrcTimer::start()/OdTvVisualizePrcTimer::stop() consistency */ class OdTvVisualize2PrcTiming { public: OdTvVisualize2PrcTiming(OdTvVisualize2PrcTimer* pTimer); ~OdTvVisualize2PrcTiming(); protected: OdTvVisualize2PrcTimer* m_pTimer; }; /** \details This object is an a catcher of the geometry used for the rendering */ class OdTvVisualize2PrcGeomCollector : public OdGiWorldDraw_Dummy, public OdGiViewportDraw_DummyEx { /** \details Different flags */ enum Flags { kTraitsValid = 1 << 0, kNeedApplyTransform = 1 << 2, kHasSubGroup = 1 << 3, kSubGroupDueToTransform = 1 << 4 }; /** \details Types for the names generation */ enum NameGenerationTypes { kMaterialName = 0, kLinetypeName = 1, kOtherName = 2, kGenericMaterialName = 3 }; protected: //DOM-IGNORE-BEGIN ODRX_HEAP_OPERATORS(); public: /** \details Constructor/Destrcutor */ OdTvVisualize2PrcGeomCollector(OdTvDatabaseId dbId, OdPrcFilePtr pDb, const OdString& modelFileName, double facetResForBrep, bool bSupportBreps, OdTvVisualize2PrcTimer* pTimer = nullptr); virtual ~OdTvVisualize2PrcGeomCollector(); /** \details Set new entity. Also 'reset' itself operation should be performed */ void setEntity(OdTvEntityId entId, bool bIsBrepEnt); /** \details Set custom font folder (for the text style) */ void setCustomFontFolder(const OdString& strCustFontFolder); /** \details Set prefix name (for the object's name generation) */ void setPrefixName(const OdString& strPrefix); /** \details Transform manipulations for holding convolution matrix */ void pushModelTransformForConvolution(const OdGeMatrix3d& xMat); void popModelTransformConvolution(); /** \details Retuns new or already created Tv material for the incoming native material */ OdTvMaterialId getTvMaterial(OdDbStub* materialId, OdUInt32& nColor, bool bForceCreate = false); /** \details Retuns new or already created Tv linetype for the incoming native linetype */ OdTvLinetypeId getTvLineType(OdDbStub* linetypeId, OdUInt32& flg); /** \details Retuns new or already created Tv raster image for the incoming gi raster image */ OdTvRasterImageId getTvImageId(const OdGiRasterImage* pImg); /** \details Retuns new or already created Tv textstyle for the incoming gi text style */ OdTvTextStyleId getTvTextStyleId(const OdGiTextStyle* pTS, double* pObliquingAngle = NULL); /** \details Sets data object handle to the user data of the Visualize object */ template< class T >void setObjectUserData(T pObjectPtr, OdDbStub* id); /** \details Set overrides for context return */ OdGiContext* context() const; /** \details Set overrides for subentitytraits return */ OdGiSubEntityTraits& subEntityTraits() const; /** \details Set overrides for regenType return */ OdGiRegenType regenType() const; /** \details Returns the recommended maximum deviation of the current vectorization, for the specified point on the curve or surface being tesselated. \param type [in] Deviation type. \param pt [in] Point on the curve. */ double deviation(const OdGiDeviationType type, const OdGePoint3d& pt) const; /** \details Set traits overrides (all that we know PRC uses) */ void setTrueColor(const OdCmEntityColor& color); void setLineType(OdDbStub* lineTypeId); void setMaterial(OdDbStub* materialId); void setTransparency(const OdCmTransparency& transparency); void setFillType(OdGiFillType fillType); void setFillPlane(const OdGeVector3d* pNormal = 0); void setDrawFlags(OdUInt32 drawFlags); void setSectionable(bool bSectionableFlag); OdCmEntityColor trueColor() const; OdDbStub* lineType() const; OdDbStub* material() const; OdCmTransparency transparency() const; OdGiFillType fillType() const; OdUInt32 drawFlags() const; bool sectionable() const; /** \details Transform manipulations overrides */ void pushModelTransform(const OdGeMatrix3d& xMat); void popModelTransform(); /** \details Geometry input overrides */ void polyline(OdInt32 nbPoints, const OdGePoint3d* pVertexList, const OdGeVector3d* pNormal = 0, OdGsMarker lBaseSubEntMarker = -1); void polygon(OdInt32 numVertices, const OdGePoint3d* vertexList); void nurbs(const OdGeNurbCurve3d& nurbsCurve); void circle(const OdGePoint3d& center, double radius, const OdGeVector3d& normal); void circularArc(const OdGePoint3d& center, double radius, const OdGeVector3d& normal, const OdGeVector3d& startVector, double sweepAngle, OdGiArcType arcType = kOdGiArcSimple); void text(const OdGePoint3d& position, const OdGeVector3d& normal, const OdGeVector3d& direction, const OdChar* msg, OdInt32 length, bool raw, const OdGiTextStyle* pTextStyle); void shell(OdInt32 numVertices, const OdGePoint3d* vertexList, OdInt32 faceListSize, const OdInt32* faceList, const OdGiEdgeData* pEdgeData = 0, const OdGiFaceData* pFaceData = 0, const OdGiVertexData* pVertexData = 0); void mesh(OdInt32 numRows, OdInt32 numColumns, const OdGePoint3d* vertexList, const OdGiEdgeData* pEdgeData = 0, const OdGiFaceData* pFaceData = 0, const OdGiVertexData* pVertexData = 0); void polypoint(OdInt32 numPoints, const OdGePoint3d* pointList, const OdCmEntityColor* pColors, const OdCmTransparency* pTransparency, const OdGeVector3d* pNormals = NULL, const OdGsMarker* pSubEntMarkers = NULL, OdInt32 nPointSize = 0); bool brep(const OdGiBrep& giBrep); void worldLine(const OdGePoint3d points[2]); void draw(const OdGiDrawable* pDrawable); protected: /** \details Methods which return opened entity */ OdTvEntityPtr getCurrentEntityPtr(OdTv::OpenMode mode = OdTv::kForRead); /** \details Methods which return opened subGroup */ OdTvSubGroupDataPtr getCurrentSubGroupPtr(); /** \details A few help methods for manupulation subgroups at the different levels */ void createNewSubGroup(bool byTransform = false); void rollbackSubGroup(bool byTransform = false); /** \details A few help methods for manupulation with traits */ void applyEffectiveTraits(const OdGiSubEntityTraitsData& effectiveTraits); void applyTraitsDifference(const OdGiSubEntityTraitsData& traits, OdUInt32 diff); OdUInt32 getTraitsDifference(const OdGiSubEntityTraitsData& t2); /** \details A few methods for manipulation with filling */ bool needShellAsColoredArea(const OdGiSubEntityTraitsData& traits, bool& bFillIn2D, bool& bSolid); bool needForceFill(const OdGiSubEntityTraitsData& traits); OdUInt8 getSpecificFillingMode(const OdGiSubEntityTraitsData& traits); /** \details A few miscellaneous methods */ OdString generateUniqName(const OdString& prefix = L"Generated_", NameGenerationTypes type = kOtherName); OdString fixFilePath(const OdString& file, OdDbBaseHostAppServices::FindFileHint hint); void getOdTvMaterialMapFromOdGiMaterialMap(const OdGiMaterialMap& giMatMap, OdTvMaterialMap& tvMatMap, OdInt16& mapperProj, OdInt16& mapperAutoTrans); OdTvRasterImageId findUnnamedImage(const OdGiRasterImage* pImg); bool isRenderFrontFaceOnly() const; void setCurrentTargetDisplayMode(const OdTvGeometryDataId& id); /** \details A few extension methods for creating geometry */ void polylineEx(OdInt32 nbPoints, const OdGePoint3d* pVertexList, const OdGeVector3d* pNormal = 0, OdGsMarker lBaseSubEntMarker = -1, bool bApplyTraits = false); void circleEx(const OdGePoint3d& center, double radius, const OdGeVector3d& normal, bool bApplyTraits = false); void textEx(const OdGePoint3d& position, const OdGeVector3d& direction, const OdGeVector3d& upVector, const OdChar* msg, OdInt32 numChars, bool raw, const OdGiTextStyle* pTextStyle, const OdGeVector3d* pExtrusion = nullptr); /** \details A few methods which create objects in Visualize database */ OdTvMaterialId createTvMaterial(const OdString& name, OdTvDatabasePtr pDb); OdTvLinetypeId createTvLinetype(const OdString& name, const OdTvLinetypeElementArray& elements, OdTvDatabasePtr pDb); OdTvTextStyleId createTvTextStyle(const OdString& name, OdTvDatabasePtr pDb); /** \details Methods for the manipulations with a flags */ bool isTraitsValid() const { return GETBIT(m_flags, kTraitsValid); } void setTraitsValid(bool b) { SETBIT(m_flags, kTraitsValid, b); } bool needApplyTransform() const { return GETBIT(m_flags, kNeedApplyTransform); } void setNeedApplyTransform(bool b) { SETBIT(m_flags, kNeedApplyTransform, b); } bool hasSubGroup() const { return GETBIT(m_flags, kHasSubGroup); } void setHasSubGroup(bool b) { SETBIT(m_flags, kHasSubGroup, b); } bool isSubGroupDueToTransform() const { return GETBIT(m_flags, kSubGroupDueToTransform); } void setSubGroupDueToTransform(bool b) { SETBIT(m_flags, kSubGroupDueToTransform, b); } SubGroupTraitsData getSubGroupTraitsData(const OdGiSubEntityTraitsData& effectiveTraits); OdTvMaterialId createGenericMaterial(const GenericMaterialData& data); GenericMaterialData getGenericMaterialData(const OdGiMaterialTraitsTaker& traitsTaker, bool bGenericColorMaterial) const; private: OdTvDatabaseId m_tvDbId; OdTvRegAppId m_appId; OdTvRegAppId m_appId_DbId; OdTvEntityId m_tvEntity; OdTvGeometryDataId m_tvSubGroup; OdTvEntityPtr m_pCurrentTvEntity; OdTv::OpenMode m_nCurrentTvEntityMode; OdTvSubGroupDataPtr m_pSubGroupData; OdGiSubEntityTraitsData m_traits; OdGiSubEntityTraitsData m_effectiveTraits; OdTvMatrix3dStack m_modelTransformStack; OdTvMatrix3dStack m_convolutionMatrixStack; //including parents (product occurances) OdUInt16 m_flags; OdTvVisualize2PrcParentsOfSubGroupStack m_parentStack; OdTvVisualize2TvObjectId m_parentObjectId; OdGiContextForPrcDatabasePtr m_pPrcContext; OdGiLinetypeRedirPtr m_pLinetyper; OdTvStubToLinetypeMap m_lineTypesMap; OdTvPrcIdToMaterialMap m_materialsPrcIdMap; OdTvTextStyleCacheToTextStyleMap m_textStyleMap; OdTvStringToRasterImageMap m_rasterImagesMap; OdTvStubToNamesMap m_generatedNames; OdString m_strCustomFolder; double m_facetResForBrep; OdTvGeometryData::TargetDisplayMode m_tvTargetDisplayMode; OdGsView::RenderMode m_renderMode; OdGiTextStyle m_textStyle; bool m_bFillPlaneSet; bool m_bSupportBreps; bool m_bIsFromPRCBrep; OdTvVisualize2PrcTimer* m_pTimer; /** \details Set of fields for the Visualize object names generation */ OdUInt16 m_nNameAttempts; OdString m_strNamePrefix; OdUInt32 m_uniqNumber; OdUInt32 m_uniqNumberMaterial; OdUInt32 m_uniqNumberGenericMaterial; OdUInt32 m_uniqNumberLinetype; std::unordered_map m_traitsSubGroupMap; std::map m_genericMaterials; }; template< class T >void OdTvVisualize2PrcGeomCollector::setObjectUserData(T pObjectPtr, OdDbStub* id) { if (pObjectPtr.isNull()) return; OdTvVisualize2PrcTiming t(m_pTimer); OdUInt64 val = m_pPrcContext->getIDByStub(id); odSwap8Bytes(&val); OdTvByteUserData* data = new OdTvByteUserData(&val, sizeof(OdUInt64), OdTvByteUserData::kCopyOwn, true); pObjectPtr->appendUserData(data, m_appId); //if need to write separate ID of the database to the user data if (!m_appId_DbId.isNull()) { //try to get database protocol extension OdDbBaseDatabase* pDatabase = m_pPrcContext->getDatabaseByStub(id); OdDbBaseDatabasePE* pDatabasePE = OdGsDbRootLinkage::getDbBaseDatabasePE(pDatabase); if (pDatabasePE) { OdDbStub* pDbStub = pDatabasePE->getId(pDatabase); if (pDbStub) { OdUInt64 valDb = m_pPrcContext->getIDByStub(pDbStub); odSwap8Bytes(&valDb); OdTvByteUserData* dataDb = new OdTvByteUserData(&valDb, sizeof(OdUInt64), OdTvByteUserData::kCopyOwn, true); pObjectPtr->appendUserData(dataDb, m_appId_DbId); } } } return; } #endif //OD_TV_PRC2VISUALIZEGEOMCOLLECTOR_H