通常,在数据库的图形矢量化过程中,矢量化器使用设置为渲染设备的颜色调色板来解析索引颜色(.dwg 数据库中的 ACI 颜色索引,.dgn 数据库中的 DgnIndex 颜色等)。有时(对于某些特定对象),可能需要完全或部分覆盖此调色板。例如,此功能可能有助于块插入矢量化,以避免重新创建具有不同颜色的块内容,并改为使用不同的调色板颜色绘制块。
对于调色板替代,OdGiSubEntityTraits 类中有两个新方法:
virtual bool pushPaletteOverride(const OdGiPalette* pOverride);
和
virtual void popPaletteOverride();
这两个方法必须始终成对调用。如果您的可绘制对象推送了调色板替代,则之后必须调用 popPaletteOverride 方法 — 这对于保持稳定的矢量化结果很重要。
在实体矢量化过程中使用调色板替代
此示例演示了如何在可绘制图形输出中使用调色板替代。
bool subWorldDraw(OdGiWorldDraw* pWd) const
{ // Create palette override
OdGiPalettePtr pPalette = OdGiPalette::createDynamic();
// Set first palette color (typically red for ACI) as blue.
pPalette->setColor(1, ODRGB(0, 0, 255));
// Inform palette that we will use this color for overriding.
pPalette->setEntryActivity(1, true);
// Set fifth palette color (typically blue for ACI) as red.
pPalette->setColor(5, ODRGB(255, 0, 0));
// Inform palette that we will use this color for overriding.
pPalette->setEntryActivity(5, true);
// Set up palette override
pWd->subEntityTraits().pushPaletteOverride(pPalette);
// Draw some geometry
pWd->subEntityTraits().setColor(1);
pWd->geometry().circle(OdGePoint3d::kOrigin, 10.0, OdGeVector3d::kZAxis);
pWd->subEntityTraits().setColor(5);
pWd->geometry().circle(OdGePoint3d::kOrigin, 15.0, OdGeVector3d::kZAxis);
// Disable palette override
pWd->subEntityTraits().popPaletteOverride(pPalette);
return true;
}
在此示例中,调色板中只有两种颜色被覆盖:第一种颜色(之前是红色)被覆盖为蓝色,第五种颜色(之前是蓝色)被覆盖为红色。之后,我们将调色板覆盖推送到调色板覆盖堆栈并绘制两个圆。较小的圆圈绘制为蓝色,另一个绘制为红色。如果禁用调色板覆盖,颜色将互换。
此代码可以使用一个特殊的辅助函数进行简化,该辅助函数在析构函数中自动调用 popPaletteOverride 方法。当绘制几何图形的源代码包含许多分支时,此辅助函数非常有用:
// Set up palette override
OdGiPaletteOverrideHelper poh(pWd->subEntityTraits(), *pPalette);
// Draw some geometry
pWd->subEntityTraits().setColor(1);
pWd->geometry().circle(OdGePoint3d::kOrigin, 10.0, OdGeVector3d::kZAxis);
pWd->subEntityTraits().setColor(5);
pWd->geometry().circle(OdGePoint3d::kOrigin, 15.0, OdGeVector3d::kZAxis);
return true;
}
这种用例是可能的,但它并不是很有帮助,因为在这种情况下,我们可以简单地使用其他颜色索引进行几何图形绘制。调色板覆盖最有用的用例是在不改变对象本身的情况下,使用覆盖的颜色绘制其他(已有的)对象。
例如,您可以从自定义实体绘制一个具有覆盖调色板颜色的块:
// Set up palette override
OdGiPaletteOverrideHelper poh(pWd->subEntityTraits(), *pPalette);
// Draw some geometry
OdDbDatabasePtr pDb(pWd->context()->database());
pWd->geometry().draw(OdDbBlockTable::cast(pDb->getBlockTableId().openObject())->getAt(OD_T("TestBlock"), OdDb::kForRead));
将调色板覆盖与覆盖功能结合使用
将调色板覆盖与覆盖功能结合使用,以覆盖数据库中所有或部分正在矢量化的对象的调色板:
class BlockRefDrawableOverrule : public OdGiDrawableOverrule
{
public:
BlockRefDrawableOverrule()
{
OdRxOverrule::setIsOverruling(true);
// Attach overrule to OdDbBlockReference entity
OdRxOverrule::addOverrule(OdDbBlockReference::desc(), this);
}
~BlockRefDrawableOverrule()
{
OdRxOverrule::removeOverrule(OdDbBlockReference::desc(), this);
OdRxOverrule::setIsOverruling(false);
}
virtual bool isApplicable(const OdRxObject* /*pOverruledSubject*/) const { return true; }
virtual bool worldDraw(const OdGiDrawable* pSubject, OdGiWorldDraw *wd)
{
OdGiPalettePtr pPalette;
// Since subSetAttributes for drawable already called we can get current drawable layer from subEntityTraits
OdDbStub *layerId = wd->subEntityTraits().layer();
OdDbBlockTableRecordPtr pLayer = OdDbObjectId(layerId).openObject();
if (pLayer->getName() == OD_T("Layer1"))
{ // Set inverted palette for block references onto Layer1.
pPalette = OdGiPalette::createDynamic();
for (OdUInt32 nClr = 0; nClr < 256; nClr++)
{
ODCOLORREF clr = OdCmEntityColor::lookUpRGB((OdUInt8)nClr);
clr = ODRGB(ODGETBLUE(clr), ODGETGREEN(clr), ODGETRED(clr));
clr = (clr & 0xFF000000) | (~clr & 0x00FFFFFF); // Invert color avoiding alpha channel
pPalette->setColor((OdInt32)nClr, clr);
pPalette->setEntryActivity((OdInt32)nClr, true);
}
}
else if (pLayer->getName() == OD_T("Layer2"))
{ // Set palette which exchanges blue and red color channels for block references onto Layer2.
pPalette = OdGiPalette::createDynamic();
for (OdUInt32 nClr = 0; nClr < 256; nClr++)
{
ODCOLORREF clr = OdCmEntityColor::lookUpRGB((OdUInt8)nClr);
clr = ODRGB(ODGETBLUE(clr), ODGETGREEN(clr), ODGETRED(clr));
// Exchange red and blue color channels.
clr = (clr & 0xFF00FF00) | ((clr & 0x00FF0000) >> 16) | ((clr & 0x000000FF) << 16);
pPalette->setColor((OdInt32)nClr, clr);
pPalette->setEntryActivity((OdInt32)nClr, true);
}
}
else if (pLayer->getName() == OD_T("Layer3"))
{ // Set grayscale palette override for block references onto Layer3
pPalette = OdGiPalette::createDynamic();
// Override first 8 palette colors using grayscale colors gradient.
pPalette->install(OdGiGrayRamp::createDynamic(8));
}
// Set up palette override
if (!pPalette.isNull())
wd->subEntityTraits().pushPaletteOverride(pPalette);
// Call subWorldDraw of original entity
const bool bResult = OdGiDrawableOverrule::worldDraw(pSubject, wd);
// Pop palette override
if (!pPalette.isNull())
wd->subEntityTraits().popPaletteOverride();
return bResult;
}
};
此类在构造函数中启用覆盖,并在析构函数中禁用覆盖。对于每个被矢量化的块引用,都会调用 worldDraw 方法,它将调色板覆盖放置在调色板覆盖堆栈中,调用原始实体绘制方法,然后从堆栈中移除调色板覆盖。
在此示例中,我们使用原始实体的图层名称来了解需要将哪个调色板覆盖放置在堆栈中——这是可能的用例之一。
使用调色板覆盖进行渲染的示例:
在此示例中,我们有一个块引用,它使用前六个调色板索引颜色来表示不同的嵌套实体(原始颜色显示在图片左上角)。
对于放置在“Layer1”上的块引用,我们对调色板中的所有 256 种颜色进行反色处理(结果显示在图片右上角)。
对于放置在“Layer2”上的块引用,我们交换调色板颜色中的红色和蓝色通道(结果显示在图片左下角)。
对于放置在“Layer3”上的块引用,我们使用灰度渐变生成器填充调色板覆盖中的前八种颜色(结果显示在图片右下角)。
结论
此功能受所有 ODA 矢量化模块支持。自 ODA 19.4 中间版本以来,它一直可用,并且可以与所有 ODA 产品一起使用。