zoukankan      html  css  js  c++  java
  • Developing associative features in AutoCAD(转)

    CAD applications often implement features or entities which are associative in nature, for example creating an extrude surface in AutoCAD 2011, by extruding a profile creates associative extrude surface. When you modify the profile the extruded surface will update itself to follow the profile.
    AutoCAD developers now can develop fascinating applications using new associative framework. There are APIs available in C++ as well as .NET to implement associative features in AutoCAD. You can download the latest ObjectARX to make use of associative framework.
    The associative framework in AutoCAD helps us to maintain relationship between objects. Relations are represented as hierarchical Networks of Objects, Actions and Dependencies between them. The core building blocks are:

    • Action - Defines behavior or intelligence of application or feature.
    • Dependency- Maintains associativity/ relations between objects and notifies changes on dependent objects.
    • Network- The associative model
    • Object- A regular AutoCAD AcDbObject/AcDbEntity being controlled by an associative action.

    Now let's code a simple action where we want to establish a relationship between a line and a circle, where length of line controls diameter of the circle. For this we need to implement an Action class derived from AcDbAssocActionBody, which provides the evaluation logic.

    //A custom action derived from AcDbAssocActionBody, establishes relationship
    //between a line and a circle. Length of the line drives diameter of the circle.
    //
    class MyActionBody : public AcDbAssocActionBody
    {
    public:
    ACRX_DECLARE_MEMBERS(MyActionBody);
    
    virtual void evaluateOverride();
    
    static Acad::ErrorStatus createInstance(AcDbObjectId lineId, AcDbObjectId circleId, AcDbObjectId& actionBodyId);
    };
    

    Establishing relationship between objects:
    This action depends on both line and circle, so we need to attach dependencies on both line and circle. Since we are going to read the length of line and write/update diameter of the circle, so we attach read dependency on line and write dependency on circle. These dependencies are owned by our action and they will ensure that line is driving entity and circle is the driven entity.

    Acad::ErrorStatus MyActionBody::createInstance(AcDbObjectId lineId, 
        AcDbObjectId circleId, AcDbObjectId& actionBodyId)
    {
        //Get the space to which network/action needs to be added.
        AcDbObjectId ownerSpaceId;
        {
            AcDbObjectPointer< AcDbEntity > pEntity(lineId, AcDb::kForRead);
            if(!eOkVerify(pEntity.openStatus()))
                return pEntity.openStatus();
            ownerSpaceId = pEntity->ownerId();
        }
    
        //create a new action and action body on the given space.
        AcDbObjectId actionId;
        AcDbAssocActionBody::createActionAndActionBodyAndPostToDatabase(
            MyActionBody::desc(), ownerSpaceId, actionId, actionBodyId);
    
        AcDbObjectPointer< AcDbAssocAction > pAction(actionId, AcDb::kForWrite);
        if(!eOkVerify(pAction.openStatus()))
            return pAction.openStatus();
    
        //Read dependency on line, to read it's length.
        AcDbAssocDependency* pDep = new AcDbAssocDependency();
        pAction->database()->addAcDbObject(pDep);
        pDep->attachToObject(lineId);
        pDep->setIsReadDependency(true);
        pDep->setIsWriteDependency(false);
        pAction->addDependency(pDep->objectId());
        pDep->close();
    
        //Write dependency on circle to set it's radius equal to length of line.
        pDep = new AcDbAssocDependency();
        pAction->database()->addAcDbObject(pDep);
        pDep->attachToObject(circleId);
        pDep->setIsReadDependency(false);
        pDep->setIsWriteDependency(true);
        pAction->addDependency(pDep->objectId());
        pDep->close();
    
        return Acad::eOk;
    }
    

    Evaluation logic:
    Now the evaluation of action needs to ensure that the desired behavior is maintained after every evaluation. This requires implementation of evaluateOverride() method on the action body class.

    void MyActionBody::evaluateOverride()
    {
        AcDbAssocEvaluationCallback* pCallback = this->currentEvaluationCallback();
    
        AcDbObjectIdArray depIds;
        Acad::ErrorStatus es = getDependencies(true, true, depIds);
        AcDbObjectId lineId, circleId;
        for(int i = 0; i < depIds.length(); ++i)
        {
            AcDbObjectPointer< AcDbAssocDependency > pDep(depIds[i], AcDb::kForRead);
            if(!eOkVerify(pDep.openStatus()))
            {
                //Reporting error to the callback.
                if(NULL != pCallback)
                {
                    AcDbObjectPointer< AcDbAssocAction > pAction(this->parentAction(), AcDb::kForRead);
                    pCallback->setActionEvaluationErrorStatus(pAction, pDep.openStatus(), depIds[i]);
                }
                setStatus(kFailedToEvaluateAssocStatus);
                return;
            }
    
            if(pDep->status() == kErasedAssocStatus)
            {
                //If any dependent object is erased, the corresponding dependency
                //will be mared as kErasedAssocStatus. For this example, we need to
                //erase the action if dependency is to be erased.
                setStatus(kErasedAssocStatus);
                return;
            }
    
            if(!pDep->isWriteDependency()) //read only dependency
                lineId = pDep->dependentOnObject();
            else if(!pDep->isReadDependency()) //write only dependency
                circleId = pDep->dependentOnObject();
        }
    
        assert(!lineId.isNull() && !circleId.isNull());
        if(lineId.isNull() || circleId.isNull())
        {
            setStatus(kFailedToEvaluateAssocStatus);
            return; //you may report some error here.
        }
        
        //Evaluate dependencies
        evaluateDependencies();
    
        double length = 0.0;
        //Use AcDbAssocObjectPointer to open line for read, so that
        //we get the cloned copy created by dragger, when line is dragged.
        AcDbAssocObjectPointer< AcDbLine > pLine(lineId, AcDb::kForRead);
        if(!eOkVerify(pLine.openStatus()))
        {
            setStatus(kFailedToEvaluateAssocStatus);
            return; //you may report some error here.
        }
    
        AcGePoint3d start, end;
        es = pLine->getStartPoint(start);
        es = pLine->getEndPoint(end);
    
        length = start.distanceTo(end);
    
        //Use AcDbAssocObjectPointer to open circle for write, so that
        //we get the clone of circle managed by dragger used to draws updated 
        //circle when line is dragged.
        AcDbAssocObjectPointer< AcDbCircle > pCircle(circleId, AcDb::kForWrite);
        if(eOkVerify(pCircle.openStatus()))
            pCircle->setRadius(length/2);
    
        setStatus(kIsUpToDateAssocStatus); //Finally set the status as uptodate.
    }

    AutoCAD的阵列就是采用AutoCAD Associative Framework实现,这块技术目前比较复杂,在.NET下实现还有困难。

    原始链接:https://ohno-iamanerd.blogspot.com/2011/01/developing-associative-features-in.html

  • 相关阅读:
    sql导数据 自增长
    只能在执行 Render() 的过程中调用 RegisterForEventValidation
    JS获取DropDownList的值
    解决IE6、IE7、IE8、Firefox兼容的两种方案
    C#日期格式化
    页面弹出窗口刷新父页面方式小结
    Dictionary Queue Stack SortedList ArrayList
    asp.net水晶报表推模式加载报表数据代码段
    JS隐藏工具栏菜单栏
    解决在SQL Server 2000的存储过程不能调试
  • 原文地址:https://www.cnblogs.com/ztcad/p/14707880.html
Copyright © 2011-2022 走看看