AcGiDrawableOverrule for custom entity not working with layer overrule for PLOT

AcGiDrawableOverrule for custom entity not working with layer overrule for PLOT

mediaengineerDE
Contributor Contributor
1,151 Views
6 Replies
Message 1 of 7

AcGiDrawableOverrule for custom entity not working with layer overrule for PLOT

mediaengineerDE
Contributor
Contributor

Hello Community,

 

we use very heavily custom entities to realize specialized drawing operations with AutoCAD. The base object of all our custom entities is AuStEntity. The AuStEntity class has a member by type AcDbHardPointerId that stores the ObjectId of an BlockTableRecord (BTR). The BTR is drawn by the entity with

AcDbBlockTableRecordPointer pBTR = nullptr;
pBTR.open(oIdBtr, AcDb::kForRead)
giDraw->rawGeometry()->draw(pBTR);

 This has been working very robust for years now.

 

Now, we want to overrule certain traits, like color and layer, from the BTR. With some very helpfull (and not trivial) sample code from the ADN I have been able to create an overrule that overrules the color, lineweight, transparency and layer of the BTR that is drawn by the AuStEntity. 

 

As an example, you can see here an object that is derived from AuStEntity and that draws a BTR which contains an AcDbSolid3d. The solid in the original BTR has the color ByLayer and is overruled to be red in this viewport. Also, the layer of the solid is overruled to the layer ____TEMP_TEST_LAYER, the object itself has the layer _custom_enity.

 

001.png

 

When freezing the layer ____TEMP_TEST_LAYER, the solid from the BTR can be frozen independent of the object layer.

 

002.gif

 

This is working with great satisfaction, EXCEPT when printing an layout with viewport, the overrule is applied to color, lineweight, transparency but NOT to the layer. When printing the layout, ths solid retains the layer from the original BTR, which is in this example an anon layer called *XX_AUST21.

 

004.gif

 

This is very unfortunate, because one of the main points of the overrule is to determine the layer that is used when printing the entity.

 

Has anybody seen this behaviour before and/or some suggestion how to fix this?

 

Thanks for your time and effort!

 

 

 

0 Likes
1,152 Views
6 Replies
Replies (6)
Message 2 of 7

tbrammer
Advisor
Advisor

It is not very common to do both: Implementing a custom entity and an overrule.

I don't know the details of your implementation so it is hard to give a profound advice here. I can imagine that you had to use some non-trivial tricks to make AcGiGeometry::draw(AcDbBlockTableRecord*) to draw a block's entities the way you want them to. I'll try to help with suggestions - although my in-depth knowledge concerning the GS is limited.

 

Does your custom entity class override Adesk::UInt32 subSetAttributes(AcGiDrawableTraits*)?
It returns a bit-sum of enum AcGiDrawable::SetAttributesFlags. As far as I understand the ARX docs, these flags should contain kDrawableIsCompoundObject in your case.

 

You are using AcGiGeometry::draw(AcDbBlockTableRecord*). It may be more robust and simple to draw the individual entities in the BTR with defined traits. You shouldn't need an additional overrule if you go this way.

  • Call entity->setAttributes(AcGiDrawableTraits *traits) and AcGiGeometry::draw(entity) for each block entity.
  • For nested BREFs use pushModelTransform(bref->blockTransform()), draw block entities, popModelTransform().

Referring to your 2nd posting regarding problems with your approach in the 3D graphics system: I think that the GS internally uses techniques to optimize block/BREF display. These techniques might not be designed for your purpose. Maybe drawing entities individually overcomes these problems - maybe for the price of reduced performance.

 

Another approach would be to temporary change the block itself using a command reactor if PLOT starts and restore it as soon as PLOT ends. But this won't cure the 3D GS problem.


Thomas Brammer ● Software Developer ● imos AGLinkedIn
If an answer solves your problem please [ACCEPT SOLUTION]. Otherwise explain why not.

0 Likes
Message 3 of 7

mediaengineerDE
Contributor
Contributor

Hello Thomas,

 

thanks for your analysis of the problem at hand.

You are right, implementing custom entities and doing overrules is more on the unusual side.

 

Let me explain the base cause for our design decision: We have thousands and thousands of different 2d and 3d blocks that we want to display and enrich with features that only custom entities can provide with great satisfaction. The blocks are sufficient complex that it is not possible to make/draw the block geometry from the custom entity itself. Therefore, the block (BTR) is the supplier (or part) of the geometry that the custom entity needs to draw.

 

When creating/inserting a custom entity into the drawing, the appropriate block is added as an AcDbBlockTableRecord (BTR) to the block table. The custom entity saves the ObjectId (oIdBtr) of the BTR and draws the BTR with

AcDbBlockTableRecordPointer pBTR = nullptr;
pBTR.open(oIdBtr, AcDb::kForRead)
giDraw->rawGeometry()->draw(pBTR);

That is almost very straightforward.

 

The problem is that the blocks itself contain multitudes of own layers, that are anonymous and therefore hidden from the user. With the layers, we control different design and visibility aspects of the displayed blocks and the overall application.  Also, some native trait of the geometry "inside" the block (like color, or in some cases the layer) needs to change according to special user needs and/or application requirements.

 

Here the fun starts, because this is NOT possible when just implementing

giDraw->rawGeometry()->draw(pBTR);

 

The workaround has been to create clones of all entities of a given block, like

AcDbSmartObjectPointer<AcDbHatch> pHatch(<ObjectId_of_entity_in_block>, AcDb::kForRead);
AcDbHatch *pHatchClone = AcDbHatch::cast(pHatch->clone());
giDraw->rawGeometry()->draw(pHatchClone);

 

With this, we are able to control the entity traits before we draw the entity. The downside is that each object in the drawing that uses the block-and-clone-mechanism creates its own clone and uses some resources while doing so. With 2d geometry that is largely ok, but trying to do this with some (large) AcDbSolid3d geometry, the performance penalty is simply too great and quickly not feasible.

 

So with 2d geometry, we stuck with the block-and-clone-mechanism.

 

With the 3d geometry, we stayed with ->draw(pBTR). But there is still the catch with the block layers and traits.

So we tried to be clever and opend the BTR before drawing the BTR and changed the entity traits (of the entities inside the block) to desired values. After draw, we opend the BTR again and reset the values to the original state.

 

This works ok in most circumstances, but fails spectacularly when trying to render the 3d block displaying custom entity: Some of the entities are just not rendered!

 

To quote the ADN (Autodesk Developer Network) on this:


This workflow upgrades the entities of the BTR and modifies them. When the object is closed, it sends an onModified() event to all 3D graphic systems (GSN is the one that renders) and this event triggers an invalidation of the graphics for that node.

The question is: How to archieve our design goals AND be able to render the 3d custom entity block geometry?

 

With some great help from the ADN (thanks, folks!), who largely contributed with sample code for the AcGiDrawableOverrule, we have been able to solve this and get sufficient performance gains while drawing the BTR's.

Also, the overhead of the additional introduced code is removed for good.

 

@tbrammer: Using the Adesk::UInt32 subSetAttributes(AcGiDrawableTraits*) would not have been solved the problem. We tried it, and the ADN also says that in this setup it would not work satisfactory.

 

BUT the downside of the AcGiDrawableOverrule is, that the layer overrule for plotting (see above) as well as the overrule for the 3D GS (see here) is not working. So there is still some significant downside to applying the overrule.

 

Concluding this post, you find our customized overrule here:

 

/* this draws the btr */
void AuStEntity::asDrawBtr(
	AcGiCommonDraw		*giDraw,
	AcDbObjectId		&oIdBtr,
	AcDbObjectId		&oIdLayer,
	Adesk::UInt16		&iEntityColor,
	AcDb::LineWeight	*lwObject,
	AcCmTransparency	&transp,
	AcGeMatrix3d		&transMat,
	AcGiWorldDraw		*pWd /* = nullptr */
)
{
	/* do nothing */
	if (oIdBtr == AcDbHardPointerId::kNull)
		return;

	/* open btr for read */
	AcDbBlockTableRecordPointer pBTR = nullptr;
	if (Acad::eOk != pBTR.open(oIdBtr, AcDb::kForRead))
	{
		oIdBtr = AcDbHardPointerId::kNull;
		return;
	}

	/* call THIS to overrule properties after draw() */
	asBtrEntityOverrule(
		giDraw,
		lwObject,
		transp,
		iEntityColor
	);

	/* geometry draw */
	if (giDraw != nullptr)
	{
		giDraw->rawGeometry()->pushModelTransform(transMat);
		giDraw->rawGeometry()->draw(pBTR);
		giDraw->rawGeometry()->popModelTransform();
	}
	else if (pWd != nullptr)
	{
		pWd->rawGeometry()->pushModelTransform(transMat);
		pWd->rawGeometry()->draw(pBTR);
		pWd->rawGeometry()->popModelTransform();
	}

	/* make sure the entity overrule is deactivated */
	asBtrEntityOverruleOff();

	/* return */
	return;

} // END
///////////////////////////////////////////////////////////////////////////////                                                       
//
// ** AuStSubEntityTraits **
class AuStSubEntityTraits : public AcGiSubEntityTraits
{
public:
    AuStSubEntityTraits(AcGiSubEntityTraits* pTraits) : m_pTraits(pTraits) {}

    /* no - ops so that entity can't change traits */
    void                    setColor(const Adesk::UInt16 color) override {}
    void                    setTrueColor(const AcCmEntityColor& color) override {}
    void                    setTransparency(const AcCmTransparency& transparency) override {};
    void                    setLineWeight(const AcDb::LineWeight lw) override {};
    #ifdef ACAD2021_AND_HIGHER
    void                    setLineWeight(const AcDb::LineWeight lw, const char lweight_index) override {};
    #endif

    /* forwarders */
    void                    setLayer(const AcDbObjectId layerId) override { m_pTraits->setLayer(layerId); }
    void                    setLineType(const AcDbObjectId linetypeId) override { m_pTraits->setLineType(linetypeId); }
    void                    setSelectionMarker(const Adesk::LongPtr markerId) override { m_pTraits->setSelectionMarker(markerId); }
    void                    setFillType(const AcGiFillType type) override { m_pTraits->setFillType(type); }
    void                    setLineTypeScale(double dScale = 1.0) override { m_pTraits->setLineTypeScale(dScale); }
    void                    setThickness(double dThickness) override { m_pTraits->setThickness(dThickness); }
    void                    setVisualStyle(const AcDbObjectId visualStyleId) override { m_pTraits->setVisualStyle(visualStyleId); }
    void                    setPlotStyleName(
        AcDb::PlotStyleNameType type,
        const AcDbObjectId& id = AcDbObjectId::kNull) override
    {
        m_pTraits->setPlotStyleName(type, id);
    }
    void                    setMaterial(const AcDbObjectId materialId) override { m_pTraits->setMaterial(materialId); }
    void                    setMapper(const AcGiMapper* mapper) override { m_pTraits->setMapper(mapper); }
    void                    setSectionable(bool bSectionable) override { m_pTraits->setSectionable(bSectionable); }
    Acad::ErrorStatus       setDrawFlags(Adesk::UInt32 flags) override { return m_pTraits->setDrawFlags(flags); }
    Acad::ErrorStatus       setShadowFlags(ShadowFlags flags) override { return m_pTraits->setShadowFlags(flags); }
    void                    setSelectionGeom(bool bSelectionflag) override { m_pTraits->setSelectionGeom(bSelectionflag); }
    void                    setFill(const AcGiFill* pFill) override { m_pTraits->setFill(pFill); }

    Adesk::UInt16           color(void) const override { return m_pTraits->color(); }
    AcCmEntityColor         trueColor(void) const override { return m_pTraits->trueColor(); }
    AcDbObjectId            layerId(void) const override { return m_pTraits->layerId(); }
    AcDbObjectId            lineTypeId(void) const override { return m_pTraits->lineTypeId(); }
    AcGiFillType            fillType(void) const override { return m_pTraits->fillType(); }
    AcDb::LineWeight        lineWeight(void) const override { return m_pTraits->lineWeight(); }
    double                  lineTypeScale(void) const override { return m_pTraits->lineTypeScale(); }
    double                  thickness(void) const override { return m_pTraits->thickness(); }
    AcDbObjectId            visualStyle(void) const override { return m_pTraits->visualStyle(); }
    AcDb::PlotStyleNameType getPlotStyleNameId(AcDbObjectId& idResult) const override { return m_pTraits->getPlotStyleNameId(idResult); }
    AcDbObjectId            materialId(void) const override { return m_pTraits->materialId(); }
    const AcGiMapper*       mapper(void) const override { return m_pTraits->mapper(); }
    bool                    sectionable(void) const override { return m_pTraits->sectionable(); }
    Adesk::UInt32           drawFlags(void) const override { return m_pTraits->drawFlags(); }
    ShadowFlags             shadowFlags(void) const override { return m_pTraits->shadowFlags(); }
    bool                    selectionGeom(void) const override { return m_pTraits->selectionGeom(); }
    AcCmTransparency        transparency(void) const override { return m_pTraits->transparency(); }
    const AcGiFill*         fill(void) const override { return m_pTraits->fill(); }

    void                    pushMarkerOverride(
        bool flag,
        const Adesk::LongPtr markerId) override
    {
        m_pTraits->pushMarkerOverride(flag, markerId);
    }
    void                    popMarkerOverride(void) override { m_pTraits->popMarkerOverride(); }
    void                    clearMarkerOverride(void) override { m_pTraits->clearMarkerOverride(); }

private:
    AcGiSubEntityTraits* m_pTraits;

};


///////////////////////////////////////////////////////////////////////////////                                                       
//
// ** AuStWorldDraw **
class AuStWorldDraw : public AcGiWorldDraw
{
public:
    AuStWorldDraw(AcGiWorldDraw* pWD) : m_pWD(pWD), m_traits(&pWD->subEntityTraits()) { }

    AcGiWorldGeometry&  geometry() const override { return m_pWD->geometry(); }
    AcGiRegenType       regenType() const override { return m_pWD->regenType(); }
    Adesk::Boolean      regenAbort() const override { return m_pWD->regenAbort(); }
    AcGiGeometry*       rawGeometry() const override { return m_pWD->rawGeometry(); }
    Adesk::Boolean      isDragging() const override { return m_pWD->isDragging(); }
    Adesk::UInt32       numberOfIsolines() const override { return m_pWD->numberOfIsolines(); }

    AcGiContext*        context() override { return m_pWD->context(); }

    double deviation(const AcGiDeviationType dev, const AcGePoint3d& pt) const override
    {
        return m_pWD->deviation(dev, pt);
    }

    AcGiSubEntityTraits& subEntityTraits() const override
    {
        /* hook sub entity traits */
        return const_cast<AuStWorldDraw*>(this)->m_traits;
    }

private:
    AcGiWorldDraw* m_pWD;
    AuStSubEntityTraits m_traits;

};


///////////////////////////////////////////////////////////////////////////////                                                       
//
// ** AuStViewportDraw **
class AuStViewportDraw : public AcGiViewportDraw
{
public:
    AuStViewportDraw(AcGiViewportDraw* pVD) : m_pVD(pVD), m_traits(&m_pVD->subEntityTraits()) { }

    AcGiViewportGeometry& geometry() const override { return m_pVD->geometry(); }
    AcGiRegenType       regenType() const override { return m_pVD->regenType(); }
    Adesk::Boolean      regenAbort() const override { return m_pVD->regenAbort(); }
    AcGiGeometry* rawGeometry() const override { return m_pVD->rawGeometry(); }
    Adesk::Boolean      isDragging() const override { return m_pVD->isDragging(); }
    Adesk::UInt32       numberOfIsolines() const override { return m_pVD->numberOfIsolines(); }
    AcGiContext* context() override { return m_pVD->context(); }

    double deviation(const AcGiDeviationType dev, const AcGePoint3d& pt) const override
    {
        return m_pVD->deviation(dev, pt);
    }

    AcGiSubEntityTraits& subEntityTraits() const override
    {
        /* hook sub entity traits */
        return const_cast<AuStViewportDraw*>(this)->m_traits;
    }

private:
    AcGiViewportDraw* m_pVD;
    AuStSubEntityTraits m_traits;

};



///////////////////////////////////////////////////////////////////////////////                                                        
// Class Macros
//
// ** AuStEntityOverrule **
/* See SDK Documentation under "Class Implementation Macros" */
/* Or rxBoiler.h */
// ACRX_DEFINE_MEMBERS(AuStEntityOverrule); /* LINKER >> rxInit() not solved */
// ACRX_CONS_DEFINE_MEMBERS(AuStEntityOverrule, AcGiDrawableOverrule, 1); /* compile error >> build abstract class not possible */
ACRX_NO_CONS_DEFINE_MEMBERS(AuStEntityOverrule, AcGiDrawableOverrule); /* build ok */

                                                                       
///////////////////////////////////////////////////////////////////////////////                                                       
// Static Member
//
// ** AuStEntityOverrule **
AuStEntityOverrule *AuStEntityOverrule::_pEntityOverrule = nullptr;


///////////////////////////////////////////////////////////////////////////////
// Constructor, Destructor
//
// ** AuStEntityOverrule **
AuStEntityOverrule::AuStEntityOverrule() 
{
    if (AuStEntityOverrule::desc() == nullptr) 
    {
        AuStEntityOverrule::rxInit();
        acrxBuildClassHierarchy();
    }
}
AuStEntityOverrule::~AuStEntityOverrule()
{
}


///////////////////////////////////////////////////////////////////////////////                                                       
// PUBLIC Class Methods
//
// ** AuStEntityOverrule **
void AuStEntityOverrule::Activate()
{    
    /* is already instantiated */
    if (_pEntityOverrule != nullptr)
        return;

    /* new overrule */
    _pEntityOverrule = new AuStEntityOverrule();

    /* add overrule */
    AcRxOverrule::addOverrule(
        AcDbEntity::desc(),
        _pEntityOverrule,
        true
    );

    /* enable overrule */
    _pEntityOverrule->Enable();
    
} // END
void AuStEntityOverrule::Deactivate(bool bUnregister /* = true */)
{
    if (_pEntityOverrule == nullptr)
        return;

    /* */
    /* Deactivate from AcRx::AppRetCode On_kUnloadAppMsg() */
    /* */

    /* disable overrule */
    _pEntityOverrule->Disable();

    if (bUnregister)
    {
        AcRxOverrule::removeOverrule(
            AcDbEntity::desc(),
            _pEntityOverrule
        );

        delete _pEntityOverrule;
        _pEntityOverrule = nullptr;
    } 

} // END
void AuStEntityOverrule::Enable() 
{ 
    m_bEnableOverrule = true; 

    if (!AcRxOverrule::isOverruling())
        AcRxOverrule::setIsOverruling(true);
}
void AuStEntityOverrule::Disable() 
{
    m_bEnableOverrule = false;

    /* these have no effect! the flag will be true even when setting it to false... */
    /* This maybe come from the overrule not removed from AcRxOverrule::removeOverrule() */
    if (AcRxOverrule::isOverruling())
        AcRxOverrule::setIsOverruling(false);
}


/////////////////////////////////////////////////
// PUBLIC Class Methods
//
// ** AuStEntityOverrule **
void AuStEntityOverrule::updateTraits(
    AcDb::LineWeight lwObject,
    AcCmTransparency &transp,
    AcDbObjectId& layerOid,
    Adesk::UInt16 &iEntityColor
)
{
    m_lwObject = lwObject;
    m_transp = transp;
    m_layerOid = layerOid;
    m_iEntityColor = iEntityColor;

    /* enable overrule >> need to disable overrule after BTR draw */
    Enable();

} // END


/////////////////////////////////////////////////
// PRIVATE Class Methods
//
// ** AuStEntityOverrule **
bool AuStEntityOverrule::isApplicable(const AcRxObject *pOverruledSubject) const
{
    /* here we need to implement our own ON/OFF flag to enable or disable the per object overrule */
    /* the IsOverruling() from the base class will be always 1, even if setIsOverruling(false) is applied */

    if (m_bEnableOverrule)
        return true;
    else
        return false;

} // END


/////////////////////////////////////////////////
// PRIVATE Class Methods
//
// ** AuStEntityOverrule **
Adesk::Boolean AuStEntityOverrule::worldDraw(AcGiDrawable* pSubject, AcGiWorldDraw* wd)
{
    /* skip entities for overrule */
    AcRxClass* rxClass = skipEntity(pSubject);
    if (rxClass != AcDbEntity::desc())
    {
        /* returning false for AcDbMText is neccessary for text and text background color */
        if (rxClass == AcDbMText::desc())
            return Adesk::kFalse;

        /* return base class world draw */
        else
            return AcGiDrawableOverrule::worldDraw(pSubject, &AuStWorldDraw(wd));
    }

    /* The default attributes are set, go ahead and override */
    setTraits(
        pSubject,
        wd,
        nullptr
    );

    /* return */
    return AcGiDrawableOverrule::worldDraw(pSubject, &AuStWorldDraw(wd));

} // END


/////////////////////////////////////////////////
// PRIVATE Class Methods
//
// ** AuStEntityOverrule **
void AuStEntityOverrule::viewportDraw(AcGiDrawable* pSubject, AcGiViewportDraw* vd)
{
    /* skip entities for overrule */
    if (AcDbEntity::desc() != skipEntity(pSubject))
        return AcGiDrawableOverrule::viewportDraw(pSubject, vd);

    /* The default attributes are set, go ahead and override */
    setTraits(
        pSubject,       
        nullptr,
        vd
    );

    /* return */
    return AcGiDrawableOverrule::viewportDraw(pSubject, vd);

} // END


/////////////////////////////////////////////////
// PRIVATE Class Methods
//
// ** AuStEntityOverrule **
void AuStEntityOverrule::setTraits(
    AcGiDrawable *pSubject,
    AcGiWorldDraw *wd,
    AcGiViewportDraw *vd
)
{
    /* get entity */
    AcDbEntity *pEnt = AcDbEntity::cast(pSubject);

    /* When the entity is part of a BTR, we check eByLayer and eByBlock */
    /* If the color of the entity is fixed (others than eByLayer || eByBlock), we DO NOT change the color! */

    /* get layer color */
    if (pEnt->colorIndex() == AuSt::eByLayer)
    {
        /* get layer color from layer */
        m_iEntityColor = getLayerColor(pEnt->layerId());
    }

    /* set color */
    if ((pEnt->colorIndex() == AuSt::eByBlock) ||
        (pEnt->colorIndex() == AuSt::eByLayer))
    {
        if      (wd != nullptr)
            wd->subEntityTraits().setColor(m_iEntityColor);
        else if (vd != nullptr)
            vd->subEntityTraits().setColor(m_iEntityColor);
    }


    /* set lineweight */
    if      (wd != nullptr)
        wd->subEntityTraits().setLineWeight(m_lwObject);
    else if (vd != nullptr)
        vd->subEntityTraits().setLineWeight(m_lwObject);


    /* set transparency */
    if      (wd != nullptr)
        wd->subEntityTraits().setTransparency(m_transp);
    else if (vd != nullptr)
        vd->subEntityTraits().setTransparency(m_transp);


    /* get layer from BTR entity when input is NULL >> is used for viewport display */
    if (m_layerOid == AcDbObjectId::kNull)
        m_layerOid = pEnt->layerId();

    /* otherwise, we use the BTR entity layer when layerOid is null */

    /* set layer */
    if      (wd != nullptr)
        wd->subEntityTraits().setLayer(m_layerOid);
    else if (vd != nullptr)
        vd->subEntityTraits().setLayer(m_layerOid);


    /* Housekeeping */
    pEnt = nullptr;


    /* return */
    return;

} // END


/////////////////////////////////////////////////
// PRIVATE Class Methods
//
// ** AuStEntityOverrule **
Adesk::UInt16 AuStEntityOverrule::getLayerColor(AcDbObjectId &oId)
{
    Adesk::UInt16 retValue = AuSt::eBlackWhite;
    AcDbLayerTableRecord* pLTR = nullptr;
    if (Acad::eOk == acdbOpenObject(
        pLTR,
        oId,
        AcDb::kForRead))
    {
        retValue = pLTR->color().colorIndex();
        pLTR->close();
    }
    pLTR = nullptr;
    return retValue;

} // END


/////////////////////////////////////////////////
// PRIVATE Class Methods
//
// ** AuStEntityOverrule **
AcRxClass* AuStEntityOverrule::skipEntity(AcGiDrawable* pSubject)
{
    /* skip AcDbAttributeDefinition */
    AcDbAttributeDefinition* pAtt = AcDbAttributeDefinition::cast(pSubject);
    if (pAtt != nullptr)
    {
        pAtt = nullptr;
        return AcDbAttributeDefinition::desc();
    }

    /* skip AcDbMText */
    AcDbMText* pMtxt = AcDbMText::cast(pSubject);
    if (pMtxt != nullptr)
    {
        pMtxt = nullptr;
        return AcDbMText::desc();
    }

    /* return */
    return AcDbEntity::desc();

} // END
0 Likes
Message 4 of 7

tbrammer
Advisor
Advisor

Ok - simply using subSetAttributes(AcGiDrawableTraits*) doesn't work. Understood.

But what about my second suggestion?

 

You are using AcGiGeometry::draw(AcDbBlockTableRecord*). It may be more robust and simple to draw the individual entities in the BTR with defined traits. You shouldn't need an additional overrule if you go this way.

  • Call entity->setAttributes(AcGiDrawableTraits *traits) and AcGiGeometry::draw(entity) for each block entity.
  • For nested BREFs use pushModelTransform(bref->blockTransform()), draw block entities, popModelTransform().

 


Thomas Brammer ● Software Developer ● imos AGLinkedIn
If an answer solves your problem please [ACCEPT SOLUTION]. Otherwise explain why not.

0 Likes
Message 5 of 7

mediaengineerDE
Contributor
Contributor

Thanks fro your follow up!

Just to make sure I understand you correctly with your second suggestion....

 

1) Open the BTR for read

2) Get the AcDbBlockTableRecordIterator

3) Iterate over all entities from the block

4) Set the desired traits (not sure if possible when opened for read)

5) Draw the entity with giDraw->rawGeometry()->draw(<entity>);

6) Reset traits to the original values, we want to preserve this (but this may not be needed, because we do not want to save the changes anyway)

7) Close the BTR

 

To be honest, that does sound a lot easier.

This is almost the same as:

 

So we tried to be clever and opend the BTR before drawing the BTR and changed the entity traits (of the entities inside the block) to desired values. After draw, we opend the BTR again and reset the values to the original state.

 

This works ok in most circumstances, but fails spectacularly when trying to render the 3d block displaying custom entity: Some of the entities are just not rendered!

 

To quote the ADN (Autodesk Developer Network) on this:

This workflow upgrades the entities of the BTR and modifies them. When the object is closed, it sends an onModified() event to all 3D graphic systems (GSN is the one that renders) and this event triggers an invalidation of the graphics for that node.

BUT we are actually not writing to the BTR.

The question is if the onModified() event i still called when closing the BTR?

 

When we started to implement our design a couple of years back, we consulted with the ADN, and they said that we would have to clone the entities from the BTR to be drawn with giDraw->rawGeometry()->draw(<entity>);

 

I will try this out, but my gut feeling tells me that there must be some catch somewhere...

0 Likes
Message 6 of 7

tbrammer
Advisor
Advisor

Yes, this is what I was thinking of. But after rethinking I'm afraid I was wrong and that it won't work because AcGiGeometry::draw(entity) will call entity->setAttributes() with the entity's layer, color... properties and thus override your call. So at the end you will need an overrule.

 

As far as I understand the docs, calling entity->setAttributes(AcGiDrawableTraits *traits)  won't acutally modify entity permanently. It will just set traits for the next draw(entity) call. So it should also be fine to call it while entity  is only read enabled. entity  will retain it's layer, color, linetype properties. 


Thomas Brammer ● Software Developer ● imos AGLinkedIn
If an answer solves your problem please [ACCEPT SOLUTION]. Otherwise explain why not.

0 Likes
Message 7 of 7

mediaengineerDE
Contributor
Contributor

Thomas, thanks for thinking and sharing about this! Always learning...

I am in contact with the ADN about this and will update this post if I know more.