/////////////////////////////////////////////////////////////////////////////// // 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. /////////////////////////////////////////////////////////////////////////////// #include "StdAfx.h" #include "DgAutoplantTorusImpl.h" #include "DgAutoplantTorus.h" #include "DgFiler.h" #include "Dg3DObject.h" #include "DgEllipse.h" #include "DgArc.h" #include "DgModel.h" #include "DgMaterialTableRecord.h" #include "DgSharedCellDefinition.h" #include "Gi/GiWorldDraw.h" #include "Ge/GeCircArc3d.h" #define MAX_CIRCLE_SEGMENTS 80 //---------------------------------------------------------- // // OdDgAutoplantTorusImpl // //---------------------------------------------------------- OdDgAutoplantTorusImpl::OdDgAutoplantTorusImpl() { m_dStartData = 0.0; m_uFlags = 0; } //---------------------------------------------------------- OdDgAutoplantTorusImpl::~OdDgAutoplantTorusImpl() { m_pCacheElement = 0; } //---------------------------------------------------------- OdResult OdDgAutoplantTorusImpl::dgnInFields(OdDgFiler* pFiler) { m_dStartData = pFiler->rdDouble(); m_ptOrigin = pFiler->rdPoint3d(); m_vrDirection = pFiler->rdVector3d(); m_vrRef = pFiler->rdVector3d(); m_dMajorRadius = pFiler->rdDouble(); m_dStartAngle = pFiler->rdDouble(); m_dSweepAngle = pFiler->rdDouble(); m_dMinorStartRadius = pFiler->rdDouble(); m_dMinorEndRadius = pFiler->rdDouble(); ODA_ASSERT_ONCE(OdZero(m_dStartData)); m_uFlags = pFiler->rdInt64(); m_pCacheElement = 0; return eOk; } //---------------------------------------------------------- void OdDgAutoplantTorusImpl::dgnOutFields(OdDgFiler* pFiler) const { pFiler->wrDouble(m_dStartData); pFiler->wrPoint3d(m_ptOrigin); pFiler->wrVector3d(m_vrDirection); pFiler->wrVector3d(m_vrRef); pFiler->wrDouble(m_dMajorRadius); pFiler->wrDouble(m_dStartAngle); pFiler->wrDouble(m_dSweepAngle); pFiler->wrDouble(m_dMinorStartRadius); pFiler->wrDouble(m_dMinorEndRadius); pFiler->wrInt64(m_uFlags); } //---------------------------------------------------------- void OdDgAutoplantTorusImpl::scaleData(double dScale) { m_ptOrigin *= dScale; m_dMajorRadius *= dScale; m_dMinorStartRadius *= dScale; m_dMinorEndRadius *= dScale; if( !m_pCacheElement.isNull() ) m_pCacheElement->transformBy(OdGeMatrix3d::scaling(dScale)); } //---------------------------------------------------------- void OdDgAutoplantTorusImpl::updateCachedElement(const OdDgAutoplantTorus* pElm) { if (m_pCacheElement) m_pCacheElement = 0; if( OdEqual(m_dMinorStartRadius, m_dMinorEndRadius, 1e-7) ) { OdDgSurfacePtr pTorus = OdDgSurface::createObject(); pTorus->setType(OdDgSurface::kSurfaceRevolution); OdDg3dObjectHelper helper(pTorus); OdGeVector3d vrRef = m_vrRef; OdGeVector3d vrDir = m_vrDirection; if (vrRef.isZeroLength()) { if (vrDir.isZeroLength()) { vrDir = OdGeVector3d::kZAxis; vrRef = OdGeVector3d::kXAxis; } else { vrRef = vrDir.perpVector(); vrRef.normalize(); } } else vrRef.normalize(); if (vrDir.isZeroLength()) vrDir = vrRef.perpVector(); else vrDir.normalize(); OdGeVector3d vrRefNorm; OdGeVector3d vrRefNormStart; OdGeVector3d vrRefNormEnd; if(vrDir.isParallelTo(vrRef) ) vrRefNorm = vrDir.perpVector(); else vrRefNorm = vrDir.crossProduct(vrRef); vrRef = vrRefNorm.crossProduct(vrDir); vrRefNormStart = vrRefNorm; vrRefNormStart.rotateBy(m_dStartAngle, vrDir); vrRefNormEnd = vrRefNormStart; vrRefNormEnd.rotateBy(m_dSweepAngle, vrDir); OdGeMatrix3d matPrimary; OdGeVector3d vrZ = vrRefNormStart; OdGeVector3d vrX = vrRef; vrX.rotateBy(m_dStartAngle, vrDir); OdGeVector3d vrY = vrZ.crossProduct(vrX); matPrimary.setCoordSystem(OdGePoint3d::kOrigin, vrX, vrY, vrZ); matPrimary.transposeIt(); OdGeQuaternion quatPrimary; quatPrimary.set(matPrimary); OdDgEllipse3dPtr pBoundary1 = OdDgEllipse3d::createObject(); pBoundary1->setOrigin(m_ptOrigin + vrX * m_dMajorRadius); pBoundary1->setPrimaryAxis(m_dMinorStartRadius); pBoundary1->setSecondaryAxis(m_dMinorStartRadius); pBoundary1->setRotation(quatPrimary); pBoundary1->setClass(pElm->getClass()); helper.addToBoundary(pBoundary1); OdDgEllipse3dPtr pBoundary2 = pBoundary1->clone(); pBoundary2->transformBy(OdGeMatrix3d::rotation(m_dSweepAngle, vrDir, m_ptOrigin)); helper.addToBoundary(pBoundary2); OdGeMatrix3d matRule; vrZ = vrDir; vrX = vrRef; vrX.rotateBy(m_dStartAngle, vrDir); vrY = vrZ.crossProduct(vrX); matRule.setCoordSystem(OdGePoint3d::kOrigin, vrX, vrY, vrZ); matRule.transposeIt(); OdGeQuaternion quatRule; quatRule.set(matRule); OdDgArc3dPtr pVertRule1 = OdDgArc3d::createObject(); pVertRule1->setOrigin(m_ptOrigin); pVertRule1->setStartAngle(0); pVertRule1->setSweepAngle(m_dSweepAngle); pVertRule1->setRotation(quatRule); pVertRule1->setPrimaryAxis(m_dMajorRadius - m_dMinorStartRadius); pVertRule1->setSecondaryAxis(m_dMajorRadius - m_dMinorStartRadius); pVertRule1->setClass(pElm->getClass() == OdDgGraphicsElement::kClassPrimary ? OdDgGraphicsElement::kClassPrimaryRule : OdDgGraphicsElement::kClassConstructionRule); helper.addToRule(pVertRule1); OdDgArc3dPtr pVertRule2 = pVertRule1->clone(); pVertRule2->setOrigin(m_ptOrigin + vrDir * m_dMinorStartRadius); pVertRule2->setPrimaryAxis(m_dMajorRadius); pVertRule2->setSecondaryAxis(m_dMajorRadius); helper.addToRule(pVertRule2); OdDgArc3dPtr pVertRule3 = pVertRule1->clone(); pVertRule3->setPrimaryAxis(m_dMajorRadius + m_dMinorStartRadius); pVertRule3->setSecondaryAxis(m_dMajorRadius + m_dMinorStartRadius); helper.addToRule(pVertRule3); OdDgArc3dPtr pVertRule4 = pVertRule1->clone(); pVertRule4->setOrigin(m_ptOrigin - vrDir * m_dMinorStartRadius); pVertRule4->setPrimaryAxis(m_dMajorRadius); pVertRule4->setSecondaryAxis(m_dMajorRadius); helper.addToRule(pVertRule4); pTorus->setPropertiesFrom(pElm, true); pTorus->setMaterial(pElm->getMaterial()); m_pCacheElement = pTorus; } } //---------------------------------------------------------- const OdDgGraphicsElement* OdDgAutoplantTorusImpl::getCachedElement(const OdDgAutoplantTorus* pElm) const { if (m_pCacheElement.isNull()) { OdDgAutoplantTorusImpl* pThis = const_cast(this); pThis->updateCachedElement(pElm); } return m_pCacheElement.get(); } //---------------------------------------------------------- void getMeshPoints(OdUInt32 nMinorSegments, OdUInt32 nMajorSegments, const OdGePoint3d& ptOrigin, const OdGeVector3d& vrDir, const OdGeVector3d& vrRef, double dSweepAngle, double dMajorRadius, double dMinorStartRadius, double dMinorEndRadius, OdArray& arrPoints) { double dMinorRadiusStep = (dMinorEndRadius - dMinorStartRadius) / (nMajorSegments - 1); double dMajorAngleStep = dSweepAngle / (nMajorSegments - 1); double dMinorAngleStep = Oda2PI / nMinorSegments; double dMinorAngle = 0; arrPoints.reserve((nMajorSegments + 1)*(nMinorSegments + 1)); OdGeVector3d vrCurRef = vrRef; double dCurMinorRadius = dMinorStartRadius; for( OdUInt32 i = 0; i < nMajorSegments; i++ ) { OdGeVector3d vrMinorRef = vrCurRef; OdGeVector3d vrMinorNorm = vrDir.crossProduct(vrMinorRef); OdGePoint3d ptMajorCircle = ptOrigin + vrCurRef * dMajorRadius; OdUInt32 uStartIndex = arrPoints.size(); for( OdUInt32 j = 0; j < nMinorSegments; j++ ) { arrPoints.push_back(ptMajorCircle + vrMinorRef * dCurMinorRadius); vrMinorRef.rotateBy(dMinorAngleStep, vrMinorNorm); } arrPoints.push_back(arrPoints[uStartIndex]); vrCurRef.rotateBy(dMajorAngleStep, vrDir); dCurMinorRadius += dMinorRadiusStep; } } //---------------------------------------------------------- double getDeviation(const OdGiWorldDraw* pWd, const OdGiDeviationType deviationType, const OdGePoint3d& ptOnCurve ) { double dRet = pWd->deviation(deviationType, ptOnCurve); if (pWd) { double dDeviationScaleFactor = 1.0; OdGeMatrix3d matWorldToModel = pWd->geometry().getWorldToModelTransform(); if (matWorldToModel != OdGeMatrix3d::kIdentity) { OdGeVector3d vrXOrd = OdGeVector3d::kXAxis; OdGeVector3d vrYOrd = OdGeVector3d::kYAxis; OdGeVector3d vrZOrd = OdGeVector3d::kZAxis; vrXOrd = vrXOrd.transformBy(matWorldToModel); vrYOrd = vrYOrd.transformBy(matWorldToModel); vrZOrd = vrZOrd.transformBy(matWorldToModel); dDeviationScaleFactor = (vrYOrd.length() < vrXOrd.length()) ? vrYOrd.length() : vrXOrd.length(); if (vrZOrd.length() < dDeviationScaleFactor) { dDeviationScaleFactor = vrZOrd.length(); } } dRet *= dDeviationScaleFactor; } return dRet; } //---------------------------------------------------------- bool OdDgAutoplantTorusImpl::drawTorusIsolines(OdGiWorldDraw* pWd) const { OdGeVector3d vrRef = m_vrRef; OdGeVector3d vrDir = m_vrDirection; if (vrRef.isZeroLength()) { if (vrDir.isZeroLength()) { vrDir = OdGeVector3d::kZAxis; vrRef = OdGeVector3d::kXAxis; } else { vrRef = vrDir.perpVector(); vrRef.normalize(); } } else vrRef.normalize(); if (vrDir.isZeroLength()) vrDir = vrRef.perpVector(); else vrDir.normalize(); OdGeVector3d vrRefNorm; OdGeVector3d vrRefNormStart; OdGeVector3d vrRefNormEnd; if (vrDir.isParallelTo(vrRef)) vrRefNorm = vrDir.perpVector(); else vrRefNorm = vrDir.crossProduct(vrRef); vrRef = vrRefNorm.crossProduct(vrDir); vrRef.rotateBy(m_dStartAngle, vrDir); OdGeVector3d vrRefEnd = vrRef; vrRefEnd.rotateBy(m_dSweepAngle, vrDir); vrRefNormStart = vrRefNorm; vrRefNormStart.rotateBy(m_dStartAngle, vrDir); vrRefNormEnd = vrRefNormStart; vrRefNormEnd.rotateBy(m_dSweepAngle, vrDir); pWd->geometry().circle(m_ptOrigin + vrRef * m_dMajorRadius, m_dMinorStartRadius, vrRefNormStart); pWd->geometry().circle(m_ptOrigin + vrRefEnd * m_dMajorRadius, m_dMinorEndRadius, vrRefNormEnd); OdGeCircArc3d circArc; double dSweepAngle = m_dSweepAngle; bool bReverseParam = false; if (dSweepAngle < 0) { vrRef.rotateBy(dSweepAngle, vrDir); bReverseParam = true; dSweepAngle *= -1; } circArc.set(m_ptOrigin, vrDir, vrRef, m_dMajorRadius, 0, dSweepAngle); if( bReverseParam ) circArc.reverseParam(); double dDeviation = getDeviation(pWd, kOdGiMaxDevForCircle, m_ptOrigin); OdUInt32 nSegments = 0; if (OdZero(m_dMajorRadius) || dDeviation > m_dMajorRadius || OdZero(dDeviation)) { if ((pWd->regenType() == kOdGiForExtents) || (pWd->regenType() == kOdGiForExplode) || OdZero(dDeviation)) nSegments = 40; else nSegments = 4; } else nSegments = static_cast(ceil(OdaPI / OD_ACOS(1. - dDeviation / m_dMajorRadius))) + 1; if (nSegments > MAX_CIRCLE_SEGMENTS) nSegments = MAX_CIRCLE_SEGMENTS; OdArray arrPoints; OdUInt32 nMinorSegments = 4; getMeshPoints(nMinorSegments, nSegments, m_ptOrigin, vrDir, vrRef, dSweepAngle, m_dMajorRadius, m_dMinorStartRadius, m_dMinorEndRadius, arrPoints); for( OdUInt32 i = 0; i < nMinorSegments; i++ ) { OdGePoint3dArray arrSegPts; arrSegPts.resize(nSegments); for (OdUInt32 j = 0; j < nSegments; j++) arrSegPts[j] = arrPoints[j * (nMinorSegments + 1) + i]; pWd->geometry().polyline(arrSegPts.size(), arrSegPts.asArrayPtr()); } return true; } //---------------------------------------------------------- bool OdDgAutoplantTorusImpl::drawTorusMesh(OdGiWorldDraw* pWd, const OdDgAutoplantTorus* pElm) const { OdGeVector3d vrRef = m_vrRef; OdGeVector3d vrDir = m_vrDirection; if (vrRef.isZeroLength()) { if (vrDir.isZeroLength()) { vrDir = OdGeVector3d::kZAxis; vrRef = OdGeVector3d::kXAxis; } else { vrRef = vrDir.perpVector(); vrRef.normalize(); } } else vrRef.normalize(); if (vrDir.isZeroLength()) vrDir = vrRef.perpVector(); else vrDir.normalize(); OdGeVector3d vrRefNorm; OdGeVector3d vrRefNormStart; OdGeVector3d vrRefNormEnd; if (vrDir.isParallelTo(vrRef)) vrRefNorm = vrDir.perpVector(); else vrRefNorm = vrDir.crossProduct(vrRef); vrRef = vrRefNorm.crossProduct(vrDir); vrRef.rotateBy(m_dStartAngle, vrDir); OdGeVector3d vrRefEnd = vrRef; OdGeVector3d vrRefStart = vrRef; vrRefEnd.rotateBy(m_dSweepAngle, vrDir); vrRefNormStart = vrRefNorm; vrRefNormStart.rotateBy(m_dStartAngle, vrDir); vrRefNormEnd = vrRefNormStart; vrRefNormEnd.rotateBy(m_dSweepAngle, vrDir); OdGeCircArc3d circArc; double dSweepAngle = m_dSweepAngle; bool bReverseParam = false; if (dSweepAngle < 0) { vrRef.rotateBy(dSweepAngle, vrDir); bReverseParam = true; dSweepAngle *= -1; } circArc.set(m_ptOrigin, vrDir, vrRef, m_dMajorRadius, 0, dSweepAngle); if (bReverseParam) circArc.reverseParam(); double dDeviation = getDeviation(pWd, kOdGiMaxDevForCircle, m_ptOrigin); OdUInt32 nSegments = 0; if (OdZero(m_dMajorRadius) || dDeviation > m_dMajorRadius || OdZero(dDeviation)) { if ((pWd->regenType() == kOdGiForExtents) || (pWd->regenType() == kOdGiForExplode) || OdZero(dDeviation)) nSegments = 40; else nSegments = 4; } else nSegments = static_cast(ceil(OdaPI / OD_ACOS(1. - dDeviation / m_dMajorRadius))) + 1; if (nSegments > MAX_CIRCLE_SEGMENTS) nSegments = MAX_CIRCLE_SEGMENTS; double dMaxMinorRadius = m_dMinorEndRadius < m_dMinorStartRadius ? m_dMinorStartRadius : m_dMinorEndRadius; OdUInt32 nMinorSegments = 4; if (OdZero(dMaxMinorRadius) || dDeviation > dMaxMinorRadius || OdZero(dDeviation)) { if ((pWd->regenType() == kOdGiForExtents) || (pWd->regenType() == kOdGiForExplode) || OdZero(dDeviation)) nMinorSegments = 40; else nMinorSegments = 4; } else nMinorSegments = static_cast(ceil(OdaPI / OD_ACOS(1. - dDeviation / dMaxMinorRadius))) + 1; if (nMinorSegments > MAX_CIRCLE_SEGMENTS) nMinorSegments = MAX_CIRCLE_SEGMENTS; OdArray arrPoints; getMeshPoints(nMinorSegments, nSegments, m_ptOrigin, vrDir, vrRef, dSweepAngle, m_dMajorRadius, m_dMinorStartRadius, m_dMinorEndRadius, arrPoints); pWd->geometry().mesh(nSegments, nMinorSegments + 1, arrPoints.asArrayPtr()); // OdGiSubEntityTraits& traits = pWd->subEntityTraits(); // // OdGiFillType oldFill = traits.fillType(); // // traits.setFillType(kOdGiFillAlways); // // pWd->geometry().polygon(nMinorSegments + 1, arrPoints.asArrayPtr()); // pWd->geometry().polygon(nMinorSegments, arrPoints.asArrayPtr() + arrPoints.size() - nMinorSegments - 1); // // traits.setFillType(oldFill); return true; } //---------------------------------------------------------- bool OdDgAutoplantTorusImpl::subWorldDraw(OdGiWorldDraw* pWd, const OdDgAutoplantTorus* pElm) const { const OdDgGraphicsElement* pCache = getCachedElement(pElm); if (pCache) return pCache->subWorldDraw(pWd); else if ((pWd->regenType() == kOdGiForExtents) || (pWd->regenType() == kOdGiStandardDisplay)) return drawTorusIsolines(pWd); else return drawTorusMesh(pWd, pElm); return true; } //---------------------------------------------------------- void OdDgAutoplantTorusImpl::subViewportDraw(OdGiViewportDraw *pVd, const OdDgAutoplantTorus* pElm) const { const OdDgGraphicsElement* pCache = getCachedElement(pElm); if(pCache) pCache->subViewportDraw(pVd); } //---------------------------------------------------------- OdResult OdDgAutoplantTorusImpl::subGetGeomExtents(OdGeExtents3d& extents, const OdDgAutoplantTorus* pElm) const { const OdDgGraphicsElement* pCache = getCachedElement(pElm); if(pCache) return pCache->subGetGeomExtents(extents); pElm->OdDgGraphicsElement::subGetGeomExtents(extents); return eOk; } //---------------------------------------------------------- OdResult OdDgAutoplantTorusImpl::subGetGeomExtents(const OdDgElementId& idView, OdGeExtents3d& extents, const OdDgAutoplantTorus* pElm) const { const OdDgGraphicsElement* pCache = getCachedElement(pElm); if (pCache) return pCache->subGetGeomExtents(idView, extents); pElm->OdDgGraphicsElement::subGetGeomExtents(idView, extents); return eOk; } //---------------------------------------------------------- OdResult OdDgAutoplantTorusImpl::subExplode(OdRxObjectPtrArray& entitySet, const OdDgAutoplantTorus* pElm) const { const OdDgGraphicsElement* pCache = getCachedElement(pElm); if(pCache) entitySet.append(pCache->clone()); pElm->explodeGeometry(entitySet); return eOk; } //---------------------------------------------------------- OdResult OdDgAutoplantTorusImpl::transformBy(const OdGeMatrix3d& xfm) { m_ptOrigin.transformBy(xfm); m_vrDirection.transformBy(xfm); m_vrRef.transformBy(xfm); double dScale = xfm.scale(); m_dMajorRadius *= dScale; m_dMinorStartRadius *= dScale; m_dMinorEndRadius *= dScale; m_pCacheElement = 0; return eOk; } //---------------------------------------------------------- OdUInt64 OdDgAutoplantTorusImpl::getFlags() const { return m_uFlags; } //---------------------------------------------------------- void OdDgAutoplantTorusImpl::setFlags(OdUInt64 uFlags) { m_uFlags = uFlags; } //---------------------------------------------------------- double OdDgAutoplantTorusImpl::getStartData() const { return m_dStartData; } //---------------------------------------------------------- void OdDgAutoplantTorusImpl::setStartData(double dStartData) { m_dStartData = dStartData; } //---------------------------------------------------------- OdGePoint3d OdDgAutoplantTorusImpl::getOrigin() const { return m_ptOrigin; } //---------------------------------------------------------- void OdDgAutoplantTorusImpl::setOrigin(const OdGePoint3d& ptOrigin) { m_ptOrigin = ptOrigin; m_pCacheElement = 0; } //---------------------------------------------------------- OdGeVector3d OdDgAutoplantTorusImpl::getDirection() const { return m_vrDirection; } //---------------------------------------------------------- void OdDgAutoplantTorusImpl::setDirection(const OdGeVector3d& vrDirection) { m_vrDirection = vrDirection; m_pCacheElement = 0; } //---------------------------------------------------------- OdGeVector3d OdDgAutoplantTorusImpl::getRefVector() const { return m_vrRef; } //---------------------------------------------------------- void OdDgAutoplantTorusImpl::setRefVector(const OdGeVector3d& vrRef) { m_vrRef = vrRef; m_pCacheElement = 0; } //---------------------------------------------------------- double OdDgAutoplantTorusImpl::getMajorRadius() const { return m_dMajorRadius; } //---------------------------------------------------------- void OdDgAutoplantTorusImpl::setMajorRadius(double dRadius) { m_dMajorRadius = dRadius; m_pCacheElement = 0; } //---------------------------------------------------------- double OdDgAutoplantTorusImpl::getMinorStartRadius() const { return m_dMinorStartRadius; } //---------------------------------------------------------- void OdDgAutoplantTorusImpl::setMinorStartRadius(double dRadius) { m_dMinorStartRadius = dRadius; m_pCacheElement = 0; } //---------------------------------------------------------- double OdDgAutoplantTorusImpl::getMinorEndRadius() const { return m_dMinorEndRadius; } //---------------------------------------------------------- void OdDgAutoplantTorusImpl::setMinorEndRadius(double dRadius) { m_dMinorEndRadius = dRadius; m_pCacheElement = 0; } //---------------------------------------------------------- double OdDgAutoplantTorusImpl::getStartAngle() const { return m_dStartAngle; } //---------------------------------------------------------- void OdDgAutoplantTorusImpl::setStartAngle(double dAngle) { m_dStartAngle = dAngle; m_pCacheElement = 0; } //---------------------------------------------------------- double OdDgAutoplantTorusImpl::getSweepAngle() const { return m_dSweepAngle; } //---------------------------------------------------------- void OdDgAutoplantTorusImpl::setSweepAngle(double dAngle) { m_dSweepAngle = dAngle; m_pCacheElement = 0; } //----------------------------------------------------------