/////////////////////////////////////////////////////////////////////////////// // 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 "OdaCommon.h" #include "DbImpCenterLineActionBody.h" #include "DbBlockTableRecord.h" #include "DbBlockReference.h" #include "DbAssocNetwork.h" #include "DbBlockTable.h" #include "DbAssocDependency.h" #include "DbAssocGeomDependency.h" #include "Ge/GeLineSeg3d.h" #include "DbAssocActionParam.h" #include "Ge/GePointOnCurve3d.h" #include "Ge/GeCurve3d.h" #include "Ge/GeScale3d.h" #include "DbLinetypeTableRecord.h" #include "DbDimAssoc.h" #include "SaveState.h" #include "DbSurface.h" #include "DbSolid.h" #include "DbLinetypeTable.h" #include "DbHostAppServices.h" #include "SmartCenterObserve.h" #define BREAK_TOLERANCE_MIN 1e-8 OdDbImpCenterLineActionBody::OdDbImpCenterLineActionBody() { } OdDbImpCenterLineActionBody::~OdDbImpCenterLineActionBody() { } OdResult OdDbImpCenterLineActionBody::dwgInFields(OdDbDwgFiler* pFiler) { OdResult res = OdDbImpSmartCenterActionBody::dwgInFields(pFiler); if (res != eOk) return res; m_pParams = OdDbSmartCenterLineParameters::createObject(); return res; } void OdDbImpCenterLineActionBody::dwgOutFields(OdDbDwgFiler* pFiler) const { OdDbImpSmartCenterActionBody::dwgOutFields(pFiler); } OdResult OdDbImpCenterLineActionBody::dxfInFields(OdDbDxfFiler* pFiler) { OdResult res = OdDbImpSmartCenterActionBody::dxfInFields(pFiler); if (res != eOk) return res; ODA_ASSERT_ONCE(pFiler->atEOF()); m_pParams = OdDbSmartCenterLineParameters::createObject(); return eOk; } void OdDbImpCenterLineActionBody::dxfOutFields(OdDbDxfFiler* pFiler) const { OdDbImpSmartCenterActionBody::dxfOutFields(pFiler); } //const OdDbSmartCenterLineParametersPtr OdDbImpCenterLineActionBody::parameters() const //{ // return m_pParams; //} // //OdDbSmartCenterLineParametersPtr& OdDbImpCenterLineActionBody::parameters() //{ // return m_pParams; //} void OdDbImpCenterLineActionBody::composeForLoad(OdDbObject *pObject, OdDb::SaveType /*format*/, OdDb::DwgVersion /*version*/, OdDbAuditInfo* /*pAuditInfo*/) { OdDbCenterLineActionBody *Body = static_cast(pObject); m_pParams->setOwner(Body); } void OdDbImpCenterLineActionBody::evaluateOverride(OdDbObjectId parentActionId) { OdDbImpSmartCenterActionBody::evaluateOverride(parentActionId); OdGeLineSeg3d ptLine1; OdGeLineSeg3d ptLine2; OdArray refDirEndArr; OdDbAssocActionPtr pAction = OdDbAssocAction::cast(parentActionId.safeOpenObject(OdDb::kForWrite)); OdDbEntityPtr bEntRef = checkAccompanying(parentActionId, pAction); if (bEntRef.isNull()) return; OdDbBlockReferencePtr bRef = OdDbBlockReference::cast(bEntRef); if (bRef.isNull()) return; OdDbAssocGeomDependencyPtr pGeomDep0 = getAssocGeomDependencyPtr(pAction, OdDb::kForWrite); OdDbAssocGeomDependencyPtr pGeomDep1 = getAssocGeomDependencyPtr(pAction, OdDb::kForWrite, 1); if (pGeomDep0.isNull() || pGeomDep1.isNull() || pGeomDep0->status()==kErasedAssocStatus || pGeomDep1->status()==kErasedAssocStatus) { if(pGeomDep0.get()) pAction->removeDependency(pGeomDep0->objectId(), true); if(pGeomDep1.get()) pAction->removeDependency(pGeomDep1->objectId(), true); pAction->setStatus(kIsUpToDateAssocStatus); return; } OdDbViewportPtr viewportV0 = getViewPortFromCompoundObject(pGeomDep0); OdDbViewportPtr viewportV1 = getViewPortFromCompoundObject(pGeomDep1); ODA_ASSERT_ONCE(viewportV0 == viewportV1); OdGeMatrix3d mViewTrans; double viewScale = 1.0; if (!viewportV0.isNull()) { OdSaveStateFunc saveView(viewportV0, &OdDbViewport::gsView, &OdDbViewport::setGsView, NULL); viewScale = viewportV0->customScale(); mViewTrans = OdDbPointRef::mswcsToPswcs(viewportV0); } edgeRefDirEndingArray(pAction, refDirEndArr); ODA_ASSERT(refDirEndArr.length() == 2); if (getCenterLineGeometry(ptLine1, 0, parentActionId) != eOk) return; if (getCenterLineGeometry(ptLine2, 1, parentActionId) != eOk) return; OdDbBlockTableRecordPtr pBR = bRef->blockTableRecord().openObject(OdDb::kForWrite); OdDbDatabase *pDb = bRef->database(); // setting "CENTER" parameters to BlockReference OdString centerMarklineType = subentLineType(pAction); OdDbLinetypeTableRecordPtr centerLTypeTableRec = OdDbImpSmartCenterActionBody::getCenterLType(pDb, centerMarklineType); OdDb::LineWeight lineWeight = OdDb::LineWeight(subentLineWeight(pAction)); bRef->setLinetype(centerLTypeTableRec->objectId()); bRef->setLinetypeScale(subentLinetypeScale(pAction)); bRef->setLineWeight(OdDb::LineWeight(lineWeight)); OdGeLineSeg3d centerLine; if (generateCenterLine(refDirEndArr, ptLine1, ptLine2, centerLine) != eOk) return; transformCenterLineAndCache(centerLine, bRef->objectId()); OdGePoint3d blPosition = centerLine.midPoint(); setCenterLineOverShoot(pAction, viewScale, centerLine); // START //START center position for BlockReference is the center of center line extents double angle = 0; OdGeVector3d normal(0, 0, 1); if (viewportV0 == viewportV1) { bRef->setNormal(normal); // inside the m_Position can be changed ones or twise, depend on normal of blockRef before. bRef->setPosition(blPosition); bRef->setRotation(angle); bRef->setScaleFactors(OdGeScale3d()); // Can be different aftter transforming BlkRef OdGeMatrix3d matr = OdGeMatrix3d::translation(OdGePoint3d::kOrigin - blPosition); centerLine.transformBy(matr); // End END OdString centerLinelineType = subentLineType(pAction); OdDbObjectIteratorPtr entityIter = pBR->newIterator(); OdDbLinePtr pLine; if (!entityIter->done()) { pLine = entityIter->entity(OdDb::kForWrite); } else { pLine = OdDbLine::createObject(); } pLine->setStartPoint(centerLine.startPoint()); pLine->setEndPoint(centerLine.endPoint()); if (!entityIter->done()) { entityIter->step(); } else { pBR->appendOdDbEntity(pLine); } } ODA_VERIFY(pAction->setStatus(kIsUpToDateAssocStatus) == eOk); } OdResult OdDbImpCenterLineActionBody::edgeRefDirEndingArray(OdDbAssocActionPtr pAction, OdArray & outputArr) { OdDbEvalVariantPtr value = OdDbEvalVariant::init((OdInt32)-1); OdString expression(""), evaluatorId(""); if (pAction->getValueParam(OD_T("EdgeRefDirectionEnding"), *value.get(), expression, evaluatorId, 0) != eOk) return eMakeMeProxy; while (!value.isNull()) { int out = value->getInt32(); outputArr.append(out); value = value->next(); } return eOk; } OdResult OdDbImpCenterLineActionBody::setEdgeRefDirEndingArray(OdDbAssocActionPtr pAction, OdArray & inputArr) { OdString errorMessages; OdString expression, evaluatorId; const OdInt32 input = OdInt32(inputArr[0]); const OdInt32 input2 = OdInt32(inputArr[1]); OdDbEvalVariantPtr value = OdDbEvalVariant::init(input); OdDbEvalVariantPtr value2 = OdDbEvalVariant::init(input2); value->setNext(value2); return pAction->setValueParam(OD_T("EdgeRefDirectionEnding"), *value.get(), expression, evaluatorId, errorMessages, false); } // OVERSHOOTS REGION enum OdResult OdDbImpCenterLineActionBody::setEndOvershoot(double newOvershoot, OdDbAssocActionPtr pAction) { const OdDbEvalVariantPtr value = OdDbEvalVariant::init(newOvershoot); OdString emptyStr(""); return pAction->setValueParam(OD_T("EndOvershoot"), *value.get(), OD_T(""), OD_T(""), emptyStr, false, 0); } enum OdResult OdDbImpCenterLineActionBody::setStartOvershoot(double newOvershoot, OdDbAssocActionPtr pAction) { const OdDbEvalVariantPtr value = OdDbEvalVariant::init(newOvershoot); OdString emptyStr(""); return pAction->setValueParam(OD_T("StartOvershoot"), *value.get(), OD_T(""), OD_T(""), emptyStr, false, 0); } double OdDbImpCenterLineActionBody::endOvershoot(OdDbAssocActionPtr pAction) const { double retD = -1.0; OdDbEvalVariantPtr value = OdDbEvalVariant::init(retD); OdString expression(""), evaluatorId(""); if (pAction->getValueParam(OD_T("EndOvershoot"), *value.get(), expression, evaluatorId, 0) != eOk) return -1.0; return value->getDouble(); } double OdDbImpCenterLineActionBody::startOvershoot(OdDbAssocActionPtr pAction) const { double retD = -1.0; OdDbEvalVariantPtr value = OdDbEvalVariant::init(retD); OdString expression(""), evaluatorId(""); if (pAction->getValueParam(OD_T("StartOvershoot"), *value.get(), expression, evaluatorId, 0) != eOk) return -1.0; return value->getDouble(); } // OVERSHOOTS REGION END // EXTENSIONS REGION enum OdResult OdDbImpCenterLineActionBody::setEndExtension(double newExtension, OdDbAssocActionPtr pAction) { const OdDbEvalVariantPtr value = OdDbEvalVariant::init(newExtension); OdString emptyStr(""); return pAction->setValueParam(OD_T("EndExtLength"), *value.get(), OD_T(""), OD_T(""), emptyStr, false, 0); } enum OdResult OdDbImpCenterLineActionBody::setStartExtension(double newExtension, OdDbAssocActionPtr pAction) { const OdDbEvalVariantPtr value = OdDbEvalVariant::init(newExtension); OdString emptyStr(""); return pAction->setValueParam(OD_T("StartExtLength"), *value.get(), OD_T(""), OD_T(""), emptyStr, false, 0); } double OdDbImpCenterLineActionBody::endExtension(OdDbAssocActionPtr pAction) const { double retD = -1.0; OdDbEvalVariantPtr value = OdDbEvalVariant::init(retD); OdString expression(""), evaluatorId(""); if (pAction->getValueParam(OD_T("EndExtLength"), *value.get(), expression, evaluatorId, 0) != eOk) return -1.0; return value->getDouble(); } double OdDbImpCenterLineActionBody::startExtension(OdDbAssocActionPtr pAction) const { double retD = -1.0; OdDbEvalVariantPtr value = OdDbEvalVariant::init(retD); OdString expression(""), evaluatorId(""); if (pAction->getValueParam(OD_T("StartExtLength"), *value.get(), expression, evaluatorId, 0) != eOk) return -1.0; return value->getDouble(); } // OVERSHOOTS REGION END ///////////////////////////////////////////////////////////////////////////////////////////////////////////////// OdResult OdDbImpCenterLineActionBody::createInstance( const OdDbFullSubentPathArray entPathArray, //OdGePoint3dArray ptsSelected, OdDbObjectId& centerLineId, OdDbObjectId& actionBodyId) { OdArray inputArr; OdDbDatabasePtr pDb; OdDbAssocActionPtr pAction; OdDbCenterLineActionBodyPtr pActionBody; OdDbAssocDependencyPtr pDependency; OdDbBlockTableRecordPtr pDestinationBTR; OdDbLinetypeTableRecordPtr centerLTypetableRec; OdDbBlockReferencePtr pCenterLineBlock; OdArray segLineArr; OdResult res = getPtrsForTree(entPathArray, pDb, pAction, pActionBody, pDependency, pDestinationBTR, centerLTypetableRec, pCenterLineBlock, segLineArr, actionBodyId); if (res != eOk) return res; OdGePoint3d ptsSelected0 = segLineArr[0].midPoint(); OdGePoint3d ptsSelected1 = segLineArr[1].midPoint(); OdGePoint3d intersectPoint(INT_MIN, INT_MIN, INT_MIN); bool ResOfIntersect = segLineArr[1].intersectWith(segLineArr[0], intersectPoint); inputArr.append(0); inputArr.append(1); // parallel case bool bParallel = !ResOfIntersect && intersectPoint == OdGePoint3d(INT_MIN, INT_MIN, INT_MIN); if (!bParallel) { OdGePointOnCurve3d closestPointN; OdGeLineSeg3d ptLineStartIntersect(segLineArr[0].startPoint(), intersectPoint); OdGeLineSeg3d ptLineEndIntersect(segLineArr[0].endPoint(), intersectPoint); if (ptLineEndIntersect.length() > ptLineStartIntersect.length()) { if (ptLineEndIntersect.getNormalPoint(ptsSelected0, closestPointN)) { inputArr[0] = 1; } else if (ptLineStartIntersect.getNormalPoint(ptsSelected0, closestPointN)) { inputArr[0] = 0; } } else { if (ptLineStartIntersect.getNormalPoint(ptsSelected0, closestPointN)) { inputArr[0] = 0; } else if (ptLineEndIntersect.getNormalPoint(ptsSelected0, closestPointN)) { inputArr[0] = 1; } } ptLineStartIntersect.set(segLineArr[1].startPoint(), intersectPoint); ptLineEndIntersect.set(segLineArr[1].endPoint(), intersectPoint); if (ptLineEndIntersect.length() > ptLineStartIntersect.length()) { if (ptLineEndIntersect.getNormalPoint(ptsSelected1, closestPointN)) { inputArr[1] = 1; } else if (ptLineStartIntersect.getNormalPoint(ptsSelected1, closestPointN)) { inputArr[1] = 0; } } else { if (ptLineStartIntersect.getNormalPoint(ptsSelected1, closestPointN)) { inputArr[1] = 0; } else if (ptLineEndIntersect.getNormalPoint(ptsSelected1, closestPointN)) { inputArr[1] = 1; } } } //Calculate EdgeRefDirEndingArray END ////////////////////////////////////////////////////////////////////// res = setParametersAndCreateCL(inputArr, pDb, pAction, pActionBody, pDependency, pDestinationBTR, centerLTypetableRec, pCenterLineBlock, centerLineId); return res; } ////////////////////////////////// OdResult OdDbImpCenterLineActionBody::getPtrsForTree( const OdDbFullSubentPathArray& entPathArray, OdDbDatabasePtr& pDb, OdDbAssocActionPtr& pAction, OdDbCenterLineActionBodyPtr& pActionBody, OdDbAssocDependencyPtr& pDependency, OdDbBlockTableRecordPtr& pDestinationBTR, OdDbLinetypeTableRecordPtr& centerLTypetableRec, OdDbBlockReferencePtr& pCenterLineBlock, OdArray& segLineArr, OdDbObjectId& actionBodyId ) { OdDbObjectId sourceEntities[2]; OdDbObjectIdArray pathArray = entPathArray[0].objectIds(); if (pathArray.length() < 1) return eInvalidInput; sourceEntities[0] = pathArray[pathArray.length() - 1]; pDb = pathArray[0].database(); pathArray.clear(); pathArray = entPathArray[1].objectIds(); if (pathArray.length() < 1) return eInvalidInput; sourceEntities[1] = pathArray[pathArray.length() - 1]; OdDbBlockTablePtr pMainBT = pDb->getBlockTableId().safeOpenObject(OdDb::kForWrite); OdDbObjectId ownerBTRId = pathArray[0].openObject()->ownerId(); OdDbBlockTableRecordPtr pOwnerSpace = ownerBTRId.safeOpenObject(OdDb::kForWrite); OdDbObjectId networkId = OdDbAssocNetwork::getInstanceFromObject(pOwnerSpace->objectId(), true); //create destination BTR pDestinationBTR = OdDbBlockTableRecord::createObject(); OdString destinationBTRname = OD_T("*U"); pDestinationBTR->setName(destinationBTRname); OdDbObjectId interID = pDb->addOdDbObject(pDestinationBTR, pMainBT->objectId()); //create center line block reference pCenterLineBlock = OdDbBlockReference::createObject(); //From 11941: For properties of Block Reference : //While creating new : setDatabaseDefaults() plus // CENTERLAYER, CENTERLTSCALE, CENTERLTYPE pCenterLineBlock->setDatabaseDefaults(pDb); centerLTypetableRec = OdDbImpSmartCenterActionBody::getCenterLType(pDb); OdDbObjectId layer = getCenterLayerId(pDb); double scale = pDb->getCENTERLTSCALE(); pCenterLineBlock->setLinetype(centerLTypetableRec->objectId()); pCenterLineBlock->setLayer(layer); pCenterLineBlock->setLinetypeScale(scale); pCenterLineBlock->setBlockTableRecord(pDestinationBTR->objectId()); pDb->addOdDbObject(pCenterLineBlock, ownerBTRId); //create action and action body //BEGIN OdDbObjectId actionId; if (eOk != createActionAndActionBodyAndPostToDatabase(OdDbCenterLineActionBody::desc(), networkId, actionId, actionBodyId)) return eInvalidInput; pActionBody = actionBodyId.safeOpenObject(OdDb::kForWrite); pAction = actionId.safeOpenObject(OdDb::kForWrite); pAction->setActionBody(actionBodyId); //END //BEGIN //geometry reference // EdgeAction references OdDbCompoundObjectId compoundObjectId; segLineArr.resize(2); for (int i = 0; i < 2; i++) { int paramIndex = i; OdDbObjectId paramId; OdString paramName = OD_T("InputEdge"); OdResult res = pAction->addParam(paramName, OdDbAssocEdgeActionParam::desc(), paramId, paramIndex); OdDbAssocEdgeActionParamPtr pEdgeActionParam = paramId.safeOpenObject(OdDb::kForRead); OdDbSubentId subent(OdDb::kEdgeSubentType, entPathArray[i].subentId().index()); compoundObjectId.setEmpty(); res = compoundObjectId.setFullPath(entPathArray[i].objectIds()); res = pEdgeActionParam->setEdgeRef(OdDbEdgeRef(compoundObjectId, subent)); // creates geom dependency res = pActionBody->getCenterLineGeometry(segLineArr[i], (i != 0)); if(eOk != res) return eInvalidInput; res = pEdgeActionParam->setEdgeSubentityGeometry(&(segLineArr[i])); } //append BTR and block ref pMainBT->add(pDestinationBTR); pOwnerSpace->appendOdDbEntity(pCenterLineBlock); //center line block reference compoundObjectId.setEmpty(); compoundObjectId.set(pCenterLineBlock->objectId()); pAction->createDependency(compoundObjectId, true, true, 0, &pDependency); return eOk; } OdResult OdDbImpCenterLineActionBody::generateCenterLine(const OdArray& refDirEndArr, const OdGeLineSeg3d& line1, const OdGeLineSeg3d& line2, OdGeLineSeg3d& centerLine) const { if (refDirEndArr.size() != 2) return eInvalidInput; OdGeTol gTolParal(1.0e-8, 1.0e-8); OdGePoint3d intersectPoint; line1.intersectWith(line2, intersectPoint, gTolParal); bool bIsParallel = line1.isParallelTo(line2, gTolParal); OdGePoint3d dirStartPoint, dirEndPoint; getEdgeRefDir(refDirEndArr, line1, line2, bIsParallel, intersectPoint, dirStartPoint, dirEndPoint); OdGePoint3d centerStart, centerEnd; if (!bIsParallel) { double length(.0); OdGeVector3d edgeDirections1 = dirStartPoint - intersectPoint; length += edgeDirections1.length(); edgeDirections1.normalize(); OdGeVector3d edgeDirections2 = dirEndPoint - intersectPoint; length += edgeDirections2.length(); edgeDirections2.normalize(); OdGeVector3d avgDirection = edgeDirections1 + edgeDirections2; OdGeLineSeg3d centerLineTemp(intersectPoint, avgDirection * length * 2); OdGePoint3d line1Start = line1.startPoint(); OdGePoint3d line1End = line1.endPoint(); OdGeVector3d line1Dir = line1.direction(); if (line1Dir.length() > 0.0 && !line1Dir.isCodirectionalTo(edgeDirections1)) { std::swap(line1Start, line1End); } OdGePoint3d line2Start = line2.startPoint(); OdGePoint3d line2End = line2.endPoint(); OdGeVector3d line2Dir = line2.direction(); if (line2Dir.length() > 0.0 && !line2Dir.isCodirectionalTo(edgeDirections2)) { std::swap(line2Start, line2End); } centerStart = intersectPoint; centerEnd = intersectPoint; if (!line1Start.isEqualTo(line2Start)) { OdGeLineSeg3d connectingLine(line1Start, line2Start); OdGePoint3d potentialIntersection; if (centerLineTemp.intersectWith(connectingLine, potentialIntersection, gTolParal) && connectingLine.isOn(potentialIntersection)) { centerStart = potentialIntersection; } } if (!line1End.isEqualTo(line2End)) { OdGeLineSeg3d connectingLine(line1End, line2End); OdGePoint3d potentialIntersection; if (centerLineTemp.intersectWith(connectingLine, potentialIntersection, gTolParal) && connectingLine.isOn(potentialIntersection)) { centerEnd = potentialIntersection; } } } else { // Get the start and end points of the first segment OdGePoint3d firstStart = line1.startPoint(); OdGePoint3d firstEnd = line1.endPoint(); // Get the start and end points of the second segment OdGePoint3d secondStart = line2.startPoint(); OdGePoint3d secondEnd = line2.endPoint(); // Create lines from the segments OdGeLine3d firstLine(firstStart, firstEnd); OdGeLine3d secondLine(secondStart, secondEnd); // Find the closest points on the first line to the points of the second line OdGePointOnCurve3d closestToSecondStart, closestToSecondEnd; firstLine.getClosestPointTo(secondStart, closestToSecondStart); firstLine.getClosestPointTo(secondEnd, closestToSecondEnd); // Get the direction of the first line OdGeVector3d firstLineDirection = line1.direction(); // Convert points on the curve to regular points OdGePoint3d closestPoint1 = closestToSecondStart; OdGePoint3d closestPoint2 = closestToSecondEnd; double maxDistance = 0.0; // Distances from the start of the first line double distToFirst = firstStart.distanceTo(firstEnd); double distToClosest1 = firstStart.distanceTo(closestPoint1); double distToClosest2 = firstStart.distanceTo(closestPoint2); maxDistance = odmax(maxDistance, odmax(distToFirst, odmax(distToClosest1, distToClosest2))); // Distances from the end of the first line double distFromEnd1 = firstEnd.distanceTo(closestPoint1); double distFromEnd2 = firstEnd.distanceTo(closestPoint2); maxDistance = odmax(maxDistance, odmax(distFromEnd1, distFromEnd2)); // Distance between the closest points double distBetweenClosest = closestPoint1.distanceTo(closestPoint2); maxDistance = odmax(maxDistance, distBetweenClosest); // Increase the maximum distance to create a working point double extensionLength = maxDistance + 1.0; // Create a working point by shifting the start of the first line in the opposite direction OdGePoint3d workPoint( firstStart.x - firstLineDirection.x * extensionLength, firstStart.y - firstLineDirection.y * extensionLength, firstStart.z - firstLineDirection.z * extensionLength ); // Determine the correct order of the second line's points // Check which point is closer to the working point double distToStart = workPoint.distanceTo(closestPoint1); double distToEnd = workPoint.distanceTo(closestPoint2); if (distToStart > distToEnd) { // Swap the points of the second line std::swap(secondStart, secondEnd); } // Calculate the midpoints to create the centerline centerStart.set( (secondStart.x + firstStart.x) * 0.5, (secondStart.y + firstStart.y) * 0.5, (secondStart.z + firstStart.z) * 0.5 ); centerEnd.set( (firstEnd.x + secondEnd.x) * 0.5, (firstEnd.y + secondEnd.y) * 0.5, (firstEnd.z + secondEnd.z) * 0.5 ); } centerLine.set(centerStart, centerEnd); return eOk; } void OdDbImpCenterLineActionBody::getEdgeRefDir( const OdArray& refDirEndArr, const OdGeLineSeg3d& line1, const OdGeLineSeg3d& line2, bool bIsParallel, const OdGePoint3d& intersectPoint, OdGePoint3d& dirStartPoint, OdGePoint3d& dirEndPoint) const { int redDirEnd1(refDirEndArr[0]), redDirEnd2(refDirEndArr[1]); if (!bIsParallel) { if (intersectPoint == line1.startPoint()) redDirEnd1 = 1; if (intersectPoint == line1.endPoint()) redDirEnd1 = 0; if (intersectPoint == line2.startPoint()) redDirEnd2 = 1; if (intersectPoint == line2.endPoint()) redDirEnd2 = 0; } dirStartPoint = (redDirEnd1 == 0) ? line1.startPoint() : line1.endPoint(); dirEndPoint = (redDirEnd2 == 0) ? line2.startPoint() : line2.endPoint(); } void OdDbImpCenterLineActionBody::transformCenterLineAndCache(OdGeLineSeg3d& centerLine, OdDbObjectId smartCenterId) { if (m_pParams.isNull()) return; OdDbImpSmartCenterLineParameters* pImpParameters = (OdDbImpSmartCenterLineParameters*)(m_pParams->impSmartCenterParameters()); if (!pImpParameters) return; OdSmartCenterEditorReactor* pEdReac = OdSmartCenterEditorReactor::getSmartCenterEditorReactor(); bool bNotUseCache = pEdReac->observerHasSmartCenter(smartCenterId, OdDbCenterLineActionBody::desc()); OdString expression, evaluatorId, pErrorMessage; OdGeVector3d vCachedCenterLineDirection = pImpParameters->cachedCenterLineDirection(expression, evaluatorId); if (!OdZero(vCachedCenterLineDirection.length()) && !bNotUseCache) { OdGeVector3d cntrDir = centerLine.direction().normalize(); double angle = cntrDir.angleTo(vCachedCenterLineDirection); if (angle > OdaPI2 && angle < 3.0 * OdaPI2) centerLine.reverseParam(); } pImpParameters->setCachedCenterLineDirection(centerLine.direction().normalize(), expression, evaluatorId, pErrorMessage); } void OdDbImpCenterLineActionBody::setCenterLineOverShoot(OdDbAssocActionPtr pAction, double viewScale, OdGeLineSeg3d& centerLine) { OdGePoint3d startPoint = centerLine.startPoint(); OdGePoint3d endPoint = centerLine.endPoint(); OdGePoint3d midPoint = centerLine.midPoint(); OdGeVector3d v1 = (startPoint - midPoint).normalize(); double extension = startExtension(pAction); double dStartOvershoot = startOvershoot(pAction) * viewScale; if (extension != OdDbSmartCenterCommonParameters::MAX_EXTENSIONS()) dStartOvershoot += extension * viewScale; startPoint += v1 * dStartOvershoot; extension = endExtension(pAction); v1 = (endPoint - midPoint).normalize(); double dEndOvershoot = endOvershoot(pAction) * viewScale; if (extension != OdDbSmartCenterCommonParameters::MAX_EXTENSIONS()) dEndOvershoot += extension * viewScale; endPoint += v1 * dEndOvershoot; centerLine.set(startPoint, endPoint); } OdResult OdDbImpCenterLineActionBody::setParametersAndCreateCL( const OdArray& inputArr, OdDbDatabase* pDb, OdDbAssocAction* pAction, OdDbCenterLineActionBody* pActionBody, OdDbAssocDependency* pBlkRefDep, OdDbBlockTableRecord* pDestinationBTR, OdDbLinetypeTableRecord* centerLTypetableRec, OdDbBlockReference* pCenterLineBlock, OdDbObjectId& centerLineId ) { ODA_ASSERT(inputArr.length() == 2); OdResult res = eSubSelectionSetEmpty; if (inputArr.length() == 2) { double scale = pDb->getCENTERLTSCALE(); OdString expression, evaluatorId, pErrorMessage; OdDbSmartCenterLineParametersPtr pParameters = OdDbSmartCenterLineParameters::createObject(); pParameters->setEdgeRefDirEndingArray(inputArr, expression, evaluatorId, pErrorMessage); pParameters->setCenterDepId(pBlkRefDep->objectId(), expression, evaluatorId, pErrorMessage); ////From 11941: While recalculating values from Parameters should be used. OdDbImpSmartCenterLineParameters* pImpParameters = (OdDbImpSmartCenterLineParameters*)(pParameters->impSmartCenterParameters()); setSubentLineWeight(pCenterLineBlock->lineWeight(), pAction); OdString centerLineLineType = centerLTypetableRec->getName(); pImpParameters->setSubentLineType(centerLineLineType, expression, evaluatorId, pErrorMessage); pImpParameters->setSubentLinetypeScale(scale, expression, evaluatorId, pErrorMessage); double exe = pDb->getCENTEREXE(); pImpParameters->setStartOvershoot(exe, expression, evaluatorId, pErrorMessage); pImpParameters->setEndOvershoot(exe, expression, evaluatorId, pErrorMessage); pActionBody->parameters() = pParameters; const_cast(pParameters)->setOwner(pActionBody); OdDbLinePtr pLine = OdDbLine::createObject(); pDestinationBTR->appendOdDbEntity(pLine); ////From 11941: For all entity properties of lines inside block I suggest to set ByBlock and // layer "0" pLine->setDatabaseDefaults(pDb); pLine->setLinetype(pDb->getLinetypeByBlockId()); pLine->setLinetypeScale(scale); pLine->setLineWeight(OdDb::kLnWtByBlock); pLine->setColor(OdCmEntityColor::kByBlock); pLine->setLayer(pDb->getLayerZeroId()); centerLineId = pLine->objectId(); res = eOk; } return res; } ////////////////////////////////// OdResult OdDbImpCenterLineActionBody::getCenterLineGeometry(OdGeLineSeg3d & refLineSegment, bool secondSeg, OdDbObjectId parentActionId) { OdResult res; OdDbAssocActionPtr pAction = OdDbAssocAction::cast(parentActionId.openObject(OdDb::kForWrite)); if (pAction.isNull()) { ODA_ASSERT(!L"Action is Null"); return eNullObjectId; } OdDbAssocGeomDependencyPtr pGeomDep, pFirstDep; OdDbObjectIdArray idDependencies; res = pAction->getDependencies(true, false, idDependencies); if (res != eOk) return res; for (unsigned int i = 0; i < idDependencies.length(); i++) { pGeomDep = OdDbAssocGeomDependency::cast(idDependencies[i].openObject()); if (!pGeomDep.isNull()) { if (!secondSeg && pFirstDep.isNull()) { break; } if (secondSeg && !pFirstDep.isNull()) { break; } pFirstDep = pGeomDep; } } if (pGeomDep.isNull()) { ODA_ASSERT(!L"Dependency is Null"); return eNullObjectId; } OdArray arrCurve; res = pGeomDep->getEdgeSubentityGeometry(arrCurve); if (res != eOk) { return res; } ODA_ASSERT(arrCurve.length() == 1 && arrCurve[0] != NULL); res = eBadObjType; if (arrCurve[0] != NULL) { if (arrCurve[0]->isKindOf(OdGe::kLineSeg3d)) { refLineSegment = *((OdGeLineSeg3d*)arrCurve[0]); res = eOk; } else { ODA_ASSERT_ONCE(!L"Unknown edge geometry"); } } for (OdArray::iterator pCurve = arrCurve.begin(); pCurve != arrCurve.end(); ++pCurve) delete (*pCurve); return res; } OdResult OdDbImpCenterLineActionBody::createInstance( const OdDbFullSubentPathArray entPathArray, OdArray inputArr, OdDbObjectId& centerLineId, OdDbObjectId& actionBodyId) { ODA_ASSERT(inputArr.length() == 2); OdDbDatabasePtr pDb; OdDbAssocActionPtr pAction; OdDbCenterLineActionBodyPtr pActionBody; OdDbAssocDependencyPtr pDependency; OdDbBlockTableRecordPtr pDestinationBTR; OdDbLinetypeTableRecordPtr centerLTypetableRec; OdDbBlockReferencePtr pCenterLineBlock; OdArray segLineArr; OdResult res = getPtrsForTree(entPathArray, pDb, pAction, pActionBody, pDependency, pDestinationBTR, centerLTypetableRec, pCenterLineBlock, segLineArr, actionBodyId); if (res != eOk) return res; return setParametersAndCreateCL(inputArr, pDb, pAction, pActionBody, pDependency, pDestinationBTR, centerLTypetableRec, pCenterLineBlock, centerLineId); }