解决ARX自定义实体类viewportDraw显示问题 - 口吕品的专栏 - CSDNBl...

来源:百度文库 编辑:神马文学网 时间:2024/10/06 20:28:44

问题描述:

在自定义实体的viewportDraw里绘制与视图相关的显示,为什么运行3dorbit(三维动态观察)时不显示,退出3dorbit后显示又正常?

经反复测试,创建自定义实体后,只要调用了修改自定义实体属性的函数,相应的实体在运行3dorbit命令过程中就不会显示

Issue

Our custom entity does all its drawing in the ViewportDraw routine, but if you display one of our entities on a 'SHADEMODE' view (Hide/Flat/Gouraud etc.) then the entity does not appear. Changing back to 2D displays the entity properly.  Why doesn't our entity display properly in SHADEMODE?

Solution

There are several problems related to this issue which make this a difficult area to develop with.  These problems are present in AutoCAD 2000i, 2002, 2004, 2005, 2006 and 2007 but not in R2000. 

Here is a summary of them, and a brief description of each workaround, which is demonstrated below:

1) If graphics are created from within viewportDraw() (ie worldDraw() returns false), the kDrawableViewIndependentViewportDraw flag must be set within setAttributes() in order to see any custom entity graphics when in a SHADEMODE other than 2D Wireframe.  This applies not only for viewport-independent graphics, but also for viewport-dependent graphics.  This is related to Change Request 282888 and has been fixed for AutoCAD 2004 upwards.

2)  When in a SHADEMODE other than 2D wireframe, viewportDraw() will be called with the incorrect regenType() intermittently, so that when zooming or panning (among other operations), the graphics will appear to switch at random.  This is Change Request 168103.  A workaround to determine the regenType() manually can be implemented by simply trying to create an AcGsView with acgsGetGsView(), which will fail in 2D shademode, but succeed in any other mode.

Note that acgsGetGsView() is part of the ObjectARX SDK (not ObjectDBX) and therefore care should be taken to get the module handle of acad.exe then get proc address - don't link your DBX to the ObjectARX SDK (See code below)

3)  When in a SHADEMODE other than 2D wireframe, AcGiViewportDraw::viewDir() will always return (0,0,1) when the regenType() is kAcGiRenderCommand (which again is intermittent).  The view direction must be calculated via AcGsView::position() and AcGsView::target().  See code workaround below. This is Change Request 136908.

4)  If while in SHADEMODE the graphics representation is changed (eg from 3d to 2d or vice versa), the 3D graphics queue must be flushed.  Even a Regen command will not always update these graphics, but AcGsView::invalidateCachedViewportGeometry() (or AcGsModel::invalidate()) does this properly.  This is not necessary when SHADEMODE is 2D wireframe.  This is by design, but is not well documented.

Solution to Problem 1 (code)

// Within the custom entity, add the kDrawableViewIndependentViewportDraw flag to 
// the base-class version of setAttributes()...
Adesk::UInt32 Cline::setAttributes(AcGiDrawableTraits* pTraits)
{
    return AcDbEntity::setAttributes(pTraits) | kDrawableViewIndependentViewportDraw;
}

Solution to Problem 2 (code)

 

// tries to get the gsView from autocad. It's fine to do this in non AutoCAD
// applications because if AutoCAD doesn't exist, we simply don't do anything
AcGsView *GetGsView(AcGiViewportDraw *mode)
{
    // see if we are running inside of autocad
    HMODULE hMod = ::GetModuleHandle(_T("acad.exe"));
    // if we are
    if(hMod)
    {
        // prepare a function pointer to get the AcGsView.
        typedef AcGsView* (*exp_acgsGetGsView)(int, bool); 
        // try to get the function pointer to acgsGetGsView
        exp_acgsGetGsView funcPtr = (exp_acgsGetGsView)::GetProcAddress(hMod, "?acgsGetGsView@@YAPAVAcGsView@@H_N@Z");
        // If this was successful, we can assume that we can use it.
        if(funcPtr)
            // all ok, return the AcGsView
            return funcPtr(mode->viewport().acadWindowId(), false);
    }
    
    return NULL;
}

Solution to Problem 3 (code) 

// function to determine the view direction.
AcGeVector3d GetViewDirection(AcGiViewportDraw *mode)
{
    // try and extract the acgsview
    AcGsView *pView = GetGsView(mode);  
    // if ok and in 3D view - we must calc our own view direction 
    if (pView) 
        // if 3D view, then we must calc our own... 
        return (pView->position()-pView->target()).normalize(); 
    else 
        // otherwise, the viewdir must be ok
        return mode->viewport().viewDir().normalize();
}

 

// Here is the overridden viewportDraw() which includes the remaining workarounds...
void Cline::viewportDraw(AcGiViewportDraw* mode)

    // Try to obtain an AcGsView for the current viewport...this will fail if it is a 2D wireframe (normal) view or if not running in AutoCAD
    // (will set pView to NULL.)
    AcGsView *pView = GetGsView(mode); // This will solve problem 2
    // You can detect if there is a conflict (ie the defect is present) like this:
    if (pView && mode->regenType() == kAcGiStandardDisplay)
        acutPrintf("Conflict in regen type ");
    
    // This is to workaround Change Request 136908...the viewDir is incorrect for regenType kRenderCommand...
    // We can calculate the view direction ourselves for a 3D view.  .
    AcGeVector3d vDir = GetViewDirection(mode); // This will solve problem 3
    
    // Draw your graphics here...perhaps they are drawn differently depending on 2D or 3D modes...
    
    
    // You must invalidate the 3D graphics cache if your graphics change between 2D and 3D modes.  
    // Perhaps this can be done within an Editor Reactor which detects when the SHADEMODE
    // command ends, and place the call to invalidateCachedViewportGeometry() there, but of course
    // that would require ObjectARX. Instead you can place the following code in the viewportDraw()
    // function, note that it will cause the function to be called twice anytime an update is needed
    // (This may be a small price to pay however).  
    
    if(pView)
    {
        pView->invalidateCachedViewportGeometry(); // This will solve problem 4
        
        // The following code also works for this purpose:
        //AcGsModel *gsModel=acgsGetGsManager()->getDBModel();
        //gsModel->invalidate(AcGsModel::kInvalidateViewportCache);
    }