/////////////////////////////////////////////////////////////////////////////// // 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. /////////////////////////////////////////////////////////////////////////////// /************************************************************************/ /* This class is an implementation of the OdDbGripPointsPE class for */ /* OdDbMline entities. */ /************************************************************************/ #include "StdAfx.h" #include "DbMlineGripPoints.h" #include "DbMline.h" #include "RxObjectImpl.h" #include "StaticRxObject.h" #include "Gi/GiBaseVectorizer.h" #include "Gi/GiGeometrySimplifier.h" #include "DbLine.h" #include "DbArc.h" // # AI - GENERATED using Claude //---------------------------------------------------------- // // OdGiDrawMLineForSnapPoints // Custom geometry extractor for MLine snap points // Reuses OdDb objects and collects snap points directly // //---------------------------------------------------------- class OdGiDrawMLineForSnapPoints : public OdGiGeometrySimplifier , public OdGiBaseVectorizer { public: OdGiDrawMLineForSnapPoints() : m_pReusableLine(OdDbLine::createObject()) , m_pReusableArc(OdDbArc::createObject()) { } // Extract snap points directly from MLine geometry OdResult extractSnapPoints(const OdDbMline* pMline, OdDb::OsnapMode osnapMode, OdGsMarker gsSelectionMark, const OdGePoint3d& pickPoint, const OdGePoint3d& lastPoint, const OdGeMatrix3d& xWorldToEye, OdGePoint3dArray& snapPoints) { if (!pMline) return eInvalidInput; // Store parameters for snap point extraction m_osnapMode = osnapMode; m_gsSelectionMark = gsSelectionMark; m_pickPoint = pickPoint; m_lastPoint = lastPoint; m_xWorldToEye = xWorldToEye; m_pSnapPoints = &snapPoints; // Process all geometry types to match original behavior m_bSkipFills = false; m_bSkipArcs = false; try { // Process all geometry through subWorldDraw to match original behavior const_cast(pMline)->subWorldDraw(this); return eOk; } catch (const OdError& err) { return err.code(); } } private: // Fast path for simple snap modes that only need vertex points bool tryDirectVertexSnapping(const OdDbMline* pMline) { // For endpoint snapping, we can directly access MLine vertices without full geometry if (m_osnapMode == OdDb::kOsModeEnd) { const int numVertices = pMline->numVertices(); if (numVertices > 0) { // Add start and end vertices directly OdGePoint3d startPt = pMline->vertexAt(0); OdGePoint3d endPt = pMline->vertexAt(numVertices - 1); m_pSnapPoints->append(startPt); if (numVertices > 1) { m_pSnapPoints->append(endPt); } return true; // Skip full geometry processing } } // For center snapping, calculate geometric center directly without geometry processing if (m_osnapMode == OdDb::kOsModeCen) { const int numVertices = pMline->numVertices(); if (numVertices > 0) { OdGePoint3d centerPt = calculateGeometricCenter(pMline); m_pSnapPoints->append(centerPt); return true; // Skip subWorldDraw completely } } return false; // Need full geometry processing } // Calculate geometric center directly from MLine vertices OdGePoint3d calculateGeometricCenter(const OdDbMline* pMline) const { const int numVertices = pMline->numVertices(); if (numVertices == 0) { return OdGePoint3d::kOrigin; } // Calculate centroid of all MLine vertices OdGePoint3d sum = OdGePoint3d::kOrigin; for (int i = 0; i < numVertices; ++i) { sum += pMline->vertexAt(i).asVector(); } return sum / (double)numVertices; } public: // OdGiBaseVectorizer overrides - capture geometry primitives virtual void polyline(OdInt32 nbPoints, const OdGePoint3d* pVertexList, const OdGeVector3d*, OdGsMarker) override { if (nbPoints >= 2 && m_pReusableLine && m_pSnapPoints) { // Process polyline as individual line segments using reusable line object for (OdInt32 i = 0; i < nbPoints - 1; ++i) { m_pReusableLine->setStartPoint(pVertexList[i]); m_pReusableLine->setEndPoint(pVertexList[i + 1]); // Get snap points from the configured line and add to collection m_pReusableLine->getOsnapPoints(m_osnapMode, m_gsSelectionMark, m_pickPoint, m_lastPoint, m_xWorldToEye, *m_pSnapPoints); } } } // OdGiGeometrySimplifier overrides - capture arcs and circles virtual void circularArcProc(const OdGePoint3d& center, double radius, const OdGeVector3d& normal, const OdGeVector3d& startVector, double sweepAngle, OdGiArcType, const OdGeVector3d*) override { // Skip arcs for snap modes that don't need them if (m_bSkipArcs || !m_pReusableArc || !m_pSnapPoints) { return; } m_pReusableArc->setCenter(center); m_pReusableArc->setRadius(radius); m_pReusableArc->setNormal(normal); // Calculate start and end angles double startAngle = OdGeVector3d::kXAxis.angleTo(startVector, normal); double endAngle = startAngle + sweepAngle; m_pReusableArc->setStartAngle(startAngle); m_pReusableArc->setEndAngle(endAngle); // Get snap points from the configured arc and add to collection m_pReusableArc->getOsnapPoints(m_osnapMode, m_gsSelectionMark, m_pickPoint, m_lastPoint, m_xWorldToEye, *m_pSnapPoints); } virtual void circleProc(const OdGePoint3d& center, double radius, const OdGeVector3d& normal, const OdGeVector3d*) override { // Skip circles for snap modes that don't need them if (m_bSkipArcs || !m_pReusableArc || !m_pSnapPoints) { return; } // Configure as full circle m_pReusableArc->setCenter(center); m_pReusableArc->setRadius(radius); m_pReusableArc->setNormal(normal); m_pReusableArc->setStartAngle(0.0); m_pReusableArc->setEndAngle(Oda2PI); // Get snap points from the configured circle and add to collection m_pReusableArc->getOsnapPoints(m_osnapMode, m_gsSelectionMark, m_pickPoint, m_lastPoint, m_xWorldToEye, *m_pSnapPoints); } // Handle polygon geometry for MLine fill areas virtual void polygon(OdInt32 nbPoints, const OdGePoint3d* pVertexList) override { // Skip fill polygons for snap modes that don't need them if (m_bSkipFills || !m_pReusableLine || !m_pSnapPoints) { return; } if (nbPoints >= 2) { // Convert polygon to individual line segments using reusable line object for (OdInt32 i = 0; i < nbPoints; ++i) { OdInt32 nextIdx = (i + 1) % nbPoints; // Wrap around for closed polygon m_pReusableLine->setStartPoint(pVertexList[i]); m_pReusableLine->setEndPoint(pVertexList[nextIdx]); // Get snap points from the configured line and add to collection m_pReusableLine->getOsnapPoints(m_osnapMode, m_gsSelectionMark, m_pickPoint, m_lastPoint, m_xWorldToEye, *m_pSnapPoints); } } } // Ignore other geometry types for snap point extraction virtual void text(const OdGePoint3d&, const OdGeVector3d&, const OdGeVector3d&, double, double, double, const OdString&) override {} virtual void xline(const OdGePoint3d&, const OdGePoint3d&) override {} virtual void ray(const OdGePoint3d&, const OdGePoint3d&) override {} // Required OdGiBaseVectorizer implementations (minimal) virtual OdGiRegenType regenType() const override { return kOdGiStandardDisplay; } virtual void draw(const OdGiDrawable*) override {} private: // Reusable OdDb objects to avoid creation overhead OdDbLinePtr m_pReusableLine; OdDbArcPtr m_pReusableArc; // Parameters for snap point extraction OdDb::OsnapMode m_osnapMode = OdDb::OsnapMode(0); OdGsMarker m_gsSelectionMark = 0; OdGePoint3d m_pickPoint; OdGePoint3d m_lastPoint; OdGeMatrix3d m_xWorldToEye; OdGePoint3dArray* m_pSnapPoints = 0; // Optimization flags to skip unnecessary geometry processing bool m_bSkipFills = false; bool m_bSkipArcs = false; }; // end # AI - GENERATED using Claude OdResult OdDbMlineGripPointsPE::getGripPoints( const OdDbEntity* ent, OdGePoint3dArray& gripPoints )const { OdDbMline* pMline = OdDbMline::cast(ent); unsigned int size = gripPoints.size(); unsigned int nVerts = pMline->numVertices(); gripPoints.resize( size + nVerts ); OdGePoint3d * pPoint = gripPoints.asArrayPtr() + size; for (unsigned int i = 0; i < nVerts; i++) { *pPoint++ = pMline->vertexAt(i); } return eOk; } OdResult OdDbMlineGripPointsPE::moveGripPointsAt( OdDbEntity* pEnt, const OdIntArray& indices, const OdGeVector3d& offset ) { unsigned size = indices.size(); if ( size == 0 ) return eOk; OdDbMline* pMline = OdDbMline::cast(pEnt); for (unsigned int i = 0; i < size; ++i) { pMline->moveVertexAt(indices[i], pMline->vertexAt(indices[i]) + offset); } return eOk; } OdResult OdDbMlineGripPointsPE::getStretchPoints( const OdDbEntity* ent, OdGePoint3dArray& stretchPoints ) const { return getGripPoints( ent, stretchPoints ); } OdResult OdDbMlineGripPointsPE::moveStretchPointsAt( OdDbEntity* ent, const OdIntArray& indices, const OdGeVector3d& offset ) { return moveGripPointsAt( ent, indices, offset ); } OdResult OdDbMlineGripPointsPE::getOsnapPoints(const OdDbEntity* ent, OdDb::OsnapMode osnapMode, OdGsMarker gsSelectionMark, const OdGePoint3d& pickPoint, const OdGePoint3d& lastPoint, const OdGeMatrix3d& xWorldToEye, OdGePoint3dArray& snapPoints) const { #if 0 // This a default way. Can be used in case of problems in performance optimized code. OdResult res; OdRxObjectPtrArray arrExploded; res = ent->explode(arrExploded); if (res != eOk) return res; for (unsigned int i = 0; i < arrExploded.size(); ++i) { OdDbEntityPtr pEnt = OdDbEntity::cast(arrExploded[i]); if (!pEnt.isNull()) { pEnt->getOsnapPoints( osnapMode, gsSelectionMark, pickPoint, lastPoint, xWorldToEye, snapPoints); } } return eOk; #else // # AI - GENERATED using Claude // This is more fast way to get snap points. Skips creation of arrExploded. OdDbMline* pMline = OdDbMline::cast(ent); if (!pMline) return eInvalidInput; // Use optimized geometry extractor that reuses objects and collects snap points directly OdStaticRxObject snapExtractor; return snapExtractor.extractSnapPoints(pMline, osnapMode, gsSelectionMark, pickPoint, lastPoint, xWorldToEye, snapPoints); #endif }