/////////////////////////////////////////////////////////////////////////////// // 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. /////////////////////////////////////////////////////////////////////////////// // ODA Platform #include "OdaCommon.h" #include "PrcCommon.h" #include "AppServices/PrcHostAppServices.h" #include "Prc2VisualizeGeomCollector.h" #include "TvDatabaseUtils.h" #include "TvSubGroupData.h" #include "Ge/GeKnotVector.h" #include "Gi/GiGeometry.h" #include "Gi/GiMaterialTraitsData.h" #include "Gi/GiMaterialItem.h" #include "Gi/GiRasterImage.h" #include "Gi/GiRasterWrappers.h" #include "Gi/GiBaseVectorizer.h" #include "Br/BrBrep.h" #include "Gi/GiBrep.h" #include "PrcTextureApplication.h" #include "PrcMaterialGeneric.h" /** \details enum for the traits difference */ enum OdTvVisualize2PrcTraitsDifference { kDiffColor = (1 << 0), kDiffLineType = (1 << 1), kDiffMaterial = (1 << 2), kDiffTransparency = (1 << 3) }; /** \details Covert dbColor to tvColor */ OdTvColorDef getTvColorFromDbColor(const OdCmEntityColor& dbColor) { //here we support that color should be ByColor OdTvColorDef color; if (dbColor.isByColor()) color.setColor(dbColor.red(), dbColor.green(), dbColor.blue()); return color; } /** \details Calculates count of edges and faces for the faces list */ void getCountShellFacesAndEdges(OdInt32 faceListSize, const OdInt32* faceList, OdInt32& nFace, OdInt32& nEdge) { nFace = 0; nEdge = 0; OdInt32 i = 0; while (i < faceListSize) { OdInt32 n = faceList[i++]; if (n > 0) nFace++; else n = -n; nEdge += n; i += n; } } /** \details Fill visualize visibilities array */ void fillVisualizeVisibilitiesArray(OdInt32 nVisibilities, OdUInt8* pVisibilities, OdTvVisibilityDefArray& visibilities, OdInt32Array* pSilhouettesIds) { visibilities.resize(nVisibilities); if (pSilhouettesIds) pSilhouettesIds->reserve(nVisibilities); for (OdInt32 i = 0; i < nVisibilities; i++) { visibilities[i] = OdTvVisibilityDef((pVisibilities[i] == 1 || pVisibilities[i] == 2) ? true : false); if (pVisibilities[i] == 2 && pSilhouettesIds) pSilhouettesIds->append(i); } return; } /** \details Fill visualize colors array for faces */ void fillVisualizeColorsArray(OdInt32 nColors, OdCmEntityColor* pColors, OdTvColorDefArray& colors) { colors.resize(nColors); for (OdInt32 i = 0; i < nColors; i++) { switch (pColors[i].colorMethod()) //we suppose that we need only normal color { case OdCmEntityColor::kByColor: colors[i] = OdTvColorDef(pColors[i].red(), pColors[i].green(), pColors[i].blue()); break; default: ODA_ASSERT(1); colors[i] = OdTvColorDef(0, 0, 0); break; } } return; } /** \details Fill visualize colors array for edges */ void fillVisualizeColorsArray(OdInt32 nColors, OdCmEntityColor* pColors, OdInt32Array& indEdges, OdTvColorDefArray& colors) { indEdges.resize(nColors); colors.resize(nColors); OdInt32 j = 0; for (OdInt32 i = 0; i < nColors; i++) { switch (pColors[i].colorMethod()) //we suppose that we need only normal color { case OdCmEntityColor::kByColor: indEdges[j] = i; colors[j] = OdTvColorDef(pColors[i].red(), pColors[i].green(), pColors[i].blue()); j++; break; default: ODA_ASSERT(1); indEdges[j] = i; colors[j] = OdTvColorDef(0, 0, 0); j++; break; } } indEdges.resize(j); colors.resize(j); return; } /** \details Convert mapper projection from GI ti Tv */ OdTvMapperDef::Projection convertFromGiMapperProjection(const OdGiMapper::Projection& p) { switch (p) { case OdGiMapper::kBox: return OdTvMapperDef::kBox; case OdGiMapper::kCylinder: return OdTvMapperDef::kCylinder; case OdGiMapper::kSphere: return OdTvMapperDef::kSphere; } return OdTvMapperDef::kPlanar; } /** \details Convert mapper auto transform from GI ti Tv */ OdTvMapperDef::AutoTransform convertFromGiMapperAutoTransform(const OdGiMapper::AutoTransform& a) { switch (a) { case OdGiMapper::kInheritAutoTransform: return OdTvMapperDef::kInheritAutoTransform; case OdGiMapper::kNone: return OdTvMapperDef::kNone; case OdGiMapper::kObject: return OdTvMapperDef::kObject; case OdGiMapper::kModel: return OdTvMapperDef::kModel; } return OdTvMapperDef::kNone; } /** \details Hlep class to access gi text style */ class OdTvVisualize2PrcTextStyleTraitsTaker : public OdGiTextStyleTraits { OdGiTextStyle m_style; public: virtual void textStyle(OdGiTextStyle& giTextStyle) const { giTextStyle = m_style; }; virtual void setTextStyle(const OdGiTextStyle& giTextStyle) { m_style = giTextStyle; } static OdSmartPtr createObject() { OdSmartPtr res = OdRxObjectImpl::createObject(); return res; } }; /** \details Timer stuff implementation */ OdTvVisualize2PrcTimer::OdTvVisualize2PrcTimer(OdPerfTimerBase * pTimer) { m_pTimer = pTimer; m_dElapsed = 0.; m_nStarts = 0; } OdTvVisualize2PrcTimer::~OdTvVisualize2PrcTimer() { m_pTimer = nullptr; m_dElapsed = 0.; m_nStarts = 0; } void OdTvVisualize2PrcTimer::start() { if (m_pTimer) { m_nStarts++; if (m_nStarts == 1) { m_pTimer->start(); } } } void OdTvVisualize2PrcTimer::stop() { if (m_pTimer) { if (m_nStarts == 0) { ODA_ASSERT(false); return; } m_nStarts--; if (m_nStarts == 0) { m_pTimer->stop(); m_dElapsed += m_pTimer->countedSec(); } } } void OdTvVisualize2PrcTimer::reset() { m_dElapsed = 0.; m_nStarts = 0; if (m_pTimer) { m_pTimer->stop(); m_pTimer->clear(); } } double OdTvVisualize2PrcTimer::time() const { return m_dElapsed; } OdTvVisualize2PrcTiming::OdTvVisualize2PrcTiming(OdTvVisualize2PrcTimer* pTimer) { m_pTimer = pTimer; if (m_pTimer) { m_pTimer->start(); } } OdTvVisualize2PrcTiming::~OdTvVisualize2PrcTiming() { if (m_pTimer) { m_pTimer->stop(); } } /** \details 'OdTvVisualize2PrcGeomCollector' methods implementation */ OdTvVisualize2PrcGeomCollector::OdTvVisualize2PrcGeomCollector(OdTvDatabaseId dbId, OdPrcFilePtr pDb, const OdString& modelFileName, double facetResForBrep, bool bSupportBreps, OdTvVisualize2PrcTimer* pTimer) : m_tvDbId(dbId) { m_flags = 0; m_pTimer = pTimer; m_nCurrentTvEntityMode = OdTv::kForRead; m_nNameAttempts = 100; m_strNamePrefix = OdTvDatabaseUtils::generateModelName(dbId, OdTvDatabaseUtils::getFileNameFromPath(modelFileName)); m_uniqNumber = 1; m_uniqNumberMaterial = 1; m_uniqNumberGenericMaterial = 1; m_uniqNumberLinetype = 1; m_tvTargetDisplayMode = OdTvGeometryData::kEveryWhere; m_renderMode = OdGsView::kGouraudShaded; m_bFillPlaneSet = false; m_facetResForBrep = facetResForBrep; m_bSupportBreps = bSupportBreps; m_bIsFromPRCBrep = false; //create user datas if (!dbId.isNull()) { bool alreadyExist = false; m_appId = dbId.openObject(OdTv::kForWrite)->registerAppName(L"ExGsVisualizeDevice", alreadyExist); bool alreadyExistDb = false; m_appId_DbId = dbId.openObject(OdTv::kForWrite)->registerAppName(L"ExGsVisualizeDevice_DBID", alreadyExistDb); } //prepare PRC context m_pPrcContext = OdGiContextForPrcDatabase::createObject(); m_pPrcContext->enableGsModel(true); m_pPrcContext->setDatabase(pDb); OdGsDbRootLinkage::initialize(); //create linetype redirection m_pLinetyper = OdGiLinetypeRedir::createObject(); m_pLinetyper->enableCache(); // Enable for both modes, but clear if model cache disabled } OdTvVisualize2PrcGeomCollector::~OdTvVisualize2PrcGeomCollector() { } void OdTvVisualize2PrcGeomCollector::setEntity(OdTvEntityId entId, bool bIsBrepEnt) { m_traitsSubGroupMap.clear(); m_tvEntity = entId; m_tvSubGroup.setNull(); m_pCurrentTvEntity = OdTvEntityPtr(); m_nCurrentTvEntityMode = OdTv::kForRead; m_traits = OdGiSubEntityTraitsData(); m_effectiveTraits = OdGiSubEntityTraitsData(); while (!m_modelTransformStack.empty()) m_modelTransformStack.pop(); //m_convolutionMatrixStack should not be deleted since it includes parents matrices m_flags = 0; while (!m_parentStack.empty()) m_parentStack.pop(); m_parentObjectId = OdTvVisualize2TvObjectId(); m_tvTargetDisplayMode = OdTvGeometryData::kEveryWhere; m_renderMode = OdGsView::kGouraudShaded; m_bFillPlaneSet = false; m_bIsFromPRCBrep = bIsBrepEnt; } void OdTvVisualize2PrcGeomCollector::setCustomFontFolder(const OdString& strCustFontFolder) { m_strCustomFolder = strCustFontFolder; } void OdTvVisualize2PrcGeomCollector::setPrefixName(const OdString& strPrefix) { m_strNamePrefix = strPrefix; } void OdTvVisualize2PrcGeomCollector::pushModelTransformForConvolution(const OdGeMatrix3d& xMat) { bool bIsEmpty = m_convolutionMatrixStack.empty(); OdGeMatrix3d* pConvM = m_convolutionMatrixStack.push(); if (!bIsEmpty) { pConvM->setToProduct(*m_convolutionMatrixStack.beforeTop(), xMat); } else { *pConvM = xMat; } return; } void OdTvVisualize2PrcGeomCollector::popModelTransformConvolution() { if (!m_convolutionMatrixStack.empty()) m_convolutionMatrixStack.pop(); return; } OdGiContext* OdTvVisualize2PrcGeomCollector::context() const { return (OdGiContext*)m_pPrcContext.get(); } OdGiSubEntityTraits& OdTvVisualize2PrcGeomCollector::subEntityTraits() const { return *const_cast(this); } OdGiRegenType OdTvVisualize2PrcGeomCollector::regenType() const { return kOdGiRenderCommand; } double OdTvVisualize2PrcGeomCollector::deviation(const OdGiDeviationType type, const OdGePoint3d& pt) const { //here we awaiting only kOdGiMaxDevForFacet if (type == kOdGiMaxDevForFacet) return 0.0003; // we suppose that it will be more than enough return 0.; } void OdTvVisualize2PrcGeomCollector::setTrueColor(const OdCmEntityColor& color) { m_effectiveTraits.setTrueColor(color); } OdCmEntityColor OdTvVisualize2PrcGeomCollector::trueColor() const { return m_effectiveTraits.trueColor(); } void OdTvVisualize2PrcGeomCollector::setLineType(OdDbStub* lineTypeId) { m_effectiveTraits.setLineType(lineTypeId); } OdDbStub* OdTvVisualize2PrcGeomCollector::lineType() const { return m_effectiveTraits.lineType(); } void OdTvVisualize2PrcGeomCollector::setMaterial(OdDbStub* materialId) { m_effectiveTraits.setMaterial(materialId); } OdDbStub* OdTvVisualize2PrcGeomCollector::material() const { return m_effectiveTraits.material(); } void OdTvVisualize2PrcGeomCollector::setTransparency(const OdCmTransparency& transparency) { m_effectiveTraits.setTransparency(transparency); } OdCmTransparency OdTvVisualize2PrcGeomCollector::transparency() const { return m_effectiveTraits.transparency(); } void OdTvVisualize2PrcGeomCollector::setFillType(OdGiFillType fillType) { m_effectiveTraits.setFillType(fillType); } OdGiFillType OdTvVisualize2PrcGeomCollector::fillType() const { return m_effectiveTraits.fillType(); } void OdTvVisualize2PrcGeomCollector::setFillPlane(const OdGeVector3d* pNormal) { m_bFillPlaneSet = (pNormal != 0); } void OdTvVisualize2PrcGeomCollector::setDrawFlags(OdUInt32 drawFlags) { m_effectiveTraits.setDrawFlags(drawFlags); } OdUInt32 OdTvVisualize2PrcGeomCollector::drawFlags() const { return m_effectiveTraits.drawFlags(); } void OdTvVisualize2PrcGeomCollector::setSectionable(bool bSectionableFlag) { m_effectiveTraits.setSectionable(bSectionableFlag); } bool OdTvVisualize2PrcGeomCollector::sectionable() const { return m_effectiveTraits.sectionable(); } void OdTvVisualize2PrcGeomCollector::pushModelTransform(const OdGeMatrix3d& xMat) { OdGeMatrix3d* pNew = m_modelTransformStack.push(); *pNew = xMat; pushModelTransformForConvolution(xMat); if (xMat == OdGeMatrix3d::kIdentity) return; setNeedApplyTransform(true); createNewSubGroup(true); if (needApplyTransform()) { OdTvVisualize2PrcTiming t(m_pTimer); //We should apply transform here if (hasSubGroup()) m_tvSubGroup.openAsSubGroup()->setModelingMatrix(xMat); else { OdTvEntityPtr entity = getCurrentEntityPtr(OdTv::kForWrite); if (!entity.isNull()) entity->setModelingMatrix(xMat); } setNeedApplyTransform(false); } } void OdTvVisualize2PrcGeomCollector::popModelTransform() { if (m_modelTransformStack.empty()) return; OdGeMatrix3d xMat = *m_modelTransformStack.top(); m_modelTransformStack.pop(); popModelTransformConvolution(); if (xMat == OdGeMatrix3d::kIdentity) return; rollbackSubGroup(true); } void OdTvVisualize2PrcGeomCollector::polyline(OdInt32 nbPoints, const OdGePoint3d* pVertexList, const OdGeVector3d* pNormal, OdGsMarker lBaseSubEntMarker) { return polylineEx(nbPoints, pVertexList, pNormal, lBaseSubEntMarker, true); } void OdTvVisualize2PrcGeomCollector::polylineEx(OdInt32 nbPoints, const OdGePoint3d* pVertexList, const OdGeVector3d* pNormal, OdGsMarker/* lBaseSubEntMarker*/, bool bApplyTraits) { if (m_tvEntity.isNull()) return; //apply effective traits at first if (bApplyTraits) applyEffectiveTraits(m_effectiveTraits); OdTvVisualize2PrcTiming t(m_pTimer); OdTvGeometryDataId resId; if (hasSubGroup()) resId = m_tvSubGroup.openAsSubGroup()->appendPolyline(nbPoints, pVertexList); else resId = getCurrentEntityPtr(OdTv::kForWrite)->appendPolyline(nbPoints, pVertexList); if (OdNonZero(m_effectiveTraits.thickness())) { OdTvPolylineDataPtr pLine = resId.openAsPolyline(); if (!pLine.isNull()) { pLine->setNormal(pNormal); pLine->setThickness(m_effectiveTraits.thickness()); } } setCurrentTargetDisplayMode(resId); return; } void OdTvVisualize2PrcGeomCollector::polygon( OdInt32 numPoints, const OdGePoint3d* vertexList) { //apply effective traits at first applyEffectiveTraits(m_effectiveTraits); ODA_ASSERT(!m_tvEntity.isNull()); OdTvVisualize2PrcTiming t(m_pTimer); //append polygon OdTvGeometryDataId id; if (hasSubGroup()) id = m_tvSubGroup.openAsSubGroup()->appendPolygon(numPoints, vertexList); else id = getCurrentEntityPtr(OdTv::kForWrite)->appendPolygon(numPoints, vertexList); setCurrentTargetDisplayMode(id); OdTvPolygonDataPtr plg = id.openAsPolygon(); if (!plg.isNull()) { bool bFill = needForceFill(m_traits); plg->setFilled(bFill); if (bFill) plg->setSpecificFillingMode(getSpecificFillingMode(m_traits)); } return; } void OdTvVisualize2PrcGeomCollector::nurbs(const OdGeNurbCurve3d& nurbsCurve) { ODA_ASSERT(!m_tvEntity.isNull()); int degree; bool rational; bool periodic; OdGeKnotVector knots; OdGePoint3dArray controlPoints; OdGeDoubleArray weights; nurbsCurve.getDefinitionData(degree, rational, periodic, knots, controlPoints, weights); //recalculate interval from [A; B] to [0; 1] //1. get interval OdGeInterval interval; nurbsCurve.getInterval(interval); double nurbStart = interval.lowerBound(); double nurbEnd = interval.upperBound(); //2. get global interval range double startKnotParam = knots[0]; double endKnotParam = knots[knots.logicalLength() - degree - 1]; //3. perform [A; B] to [0; 1] double start = 0.; double end = 1.; double intervalRange = endKnotParam - startKnotParam; if (!OdZero(intervalRange)) { start = (nurbStart - startKnotParam) / intervalRange; end = (nurbEnd - startKnotParam) / intervalRange; } if ((start < 0. || start > 1.) || (end < 0. || end > 1.) || start > end) { start = 0.; end = 1.; } //apply effective traits at first applyEffectiveTraits(m_effectiveTraits); OdTvVisualize2PrcTiming t(m_pTimer); OdTvGeometryDataId resId; if (hasSubGroup()) resId = m_tvSubGroup.openAsSubGroup()->appendNurbs(degree, controlPoints.length(), controlPoints.asArrayPtr(), weights.asArrayPtr(), knots.length(), knots.asArrayPtr(), start, end, knots.tolerance()); else resId = getCurrentEntityPtr(OdTv::kForWrite)->appendNurbs(degree, controlPoints.length(), controlPoints.asArrayPtr(), weights.asArrayPtr(), knots.length(), knots.asArrayPtr(), start, end, knots.tolerance()); setCurrentTargetDisplayMode(resId); return; } void OdTvVisualize2PrcGeomCollector::circle(const OdGePoint3d& center, double radius, const OdGeVector3d& normal) { return circleEx(center, radius, normal, true); } void OdTvVisualize2PrcGeomCollector::circleEx(const OdGePoint3d& center, double radius, const OdGeVector3d& normal, bool bApplyTraits) { ODA_ASSERT(!m_tvEntity.isNull()); //apply effective traits at first if (bApplyTraits) applyEffectiveTraits(m_effectiveTraits); OdTvVisualize2PrcTiming t(m_pTimer); OdTvGeometryDataId resId; if (hasSubGroup()) resId = m_tvSubGroup.openAsSubGroup()->appendCircle(center, radius, normal); else resId = getCurrentEntityPtr(OdTv::kForWrite)->appendCircle(center, radius, normal); if (OdNonZero(m_effectiveTraits.thickness())) { OdGeVector3d extNorm = normal.normal(); double thickness = m_effectiveTraits.thickness(); if (extNorm.dotProduct(normal) < 0) thickness *= -1.0; OdTvCircleDataPtr pCircle = resId.openAsCircle(); if (!pCircle.isNull()) pCircle->setThickness(m_effectiveTraits.thickness()); } //eo extrusion... setCurrentTargetDisplayMode(resId); return; } void OdTvVisualize2PrcGeomCollector::circularArc(const OdGePoint3d& center, double radius, const OdGeVector3d& normal, const OdGeVector3d& startVector, double sweepAngle, OdGiArcType arcType) { ODA_ASSERT(!m_tvEntity.isNull()); //apply effective traits at first applyEffectiveTraits(m_effectiveTraits); if (fabs(sweepAngle - Oda2PI) < 1e-6) { circleEx(center, radius, normal); return; } OdGeCircArc3d arc(center, normal, startVector, radius, 0., sweepAngle); OdTvVisualize2PrcTiming t(m_pTimer); OdTvGeometryDataId resId; if (hasSubGroup()) resId = m_tvSubGroup.openAsSubGroup()->appendCircleArc(arc.evalPoint(0.), arc.evalPoint(sweepAngle / 2.), arc.evalPoint(sweepAngle)); else resId = getCurrentEntityPtr(OdTv::kForWrite)->appendCircleArc(arc.evalPoint(0.), arc.evalPoint(sweepAngle / 2.), arc.evalPoint(sweepAngle)); if (OdNonZero(m_effectiveTraits.thickness())) { OdTvCircleArcDataPtr pArc = resId.openAsCircleArc(); if (!pArc.isNull()) { //Arc normal and plane normal are different, but plane normal is used in conveour to calculate extrusion. //The same is in ARX, so it is correct. //So, we have to specify extrusion sign. OdGePlane primitivePlane; primitivePlane.set(pArc->getStart(), pArc->getMiddle(), pArc->getEnd()); OdTvVector primitiveNormal = primitivePlane.normal(); OdTvVector extrusionNormal = normal.normal(); if (primitiveNormal.dotProduct(extrusionNormal) < 0) { pArc->setThickness(-1.0 * m_effectiveTraits.thickness()); } else { pArc->setThickness(m_effectiveTraits.thickness()); } } }//eo extrusion setCurrentTargetDisplayMode(resId); return; } void OdTvVisualize2PrcGeomCollector::textEx(const OdGePoint3d& position, const OdGeVector3d& direction, const OdGeVector3d& upVector, const OdChar* msg, OdInt32 numChars, bool raw, const OdGiTextStyle* pTextStyle, const OdGeVector3d* pExtrusion) { if (m_tvEntity.isNull()) { ODA_FAIL(); return; } OdString msgStr; if (numChars > 0) { msgStr = OdString(msg, numChars); } else { msgStr = OdString(msg); } bool bU = false; bool bO = false; bool bK = false; if (msgStr.getLength() > 3 && !raw) { OdString testStr = msgStr.left(3); if (testStr == OD_T("%%U")) bU = true; if (testStr == OD_T("%%O")) bO = true; if (testStr == OD_T("%%K")) bK = true; } if (bU || bO || bK) { msgStr = msgStr.right(msgStr.getLength() - 3); } //create and setup text data OdTvGeometryDataId textId; { OdTvVisualize2PrcTiming t(m_pTimer); if (hasSubGroup()) textId = m_tvSubGroup.openAsSubGroup()->appendText(position, msgStr); else textId = getCurrentEntityPtr(OdTv::kForWrite)->appendText(position, msgStr); setCurrentTargetDisplayMode(textId); OdTvTextDataPtr pText = textId.openAsText(); if (pText.isNull()) { ODA_ASSERT(false); return; } pText->setPosition(position); } OdGeVector3d d1 = direction, u1 = upVector; if (!d1.isZeroLength()) d1.normalize(); if (!u1.isZeroLength()) u1.normalize(); OdGeVector3d v_normal = d1.crossProduct(u1); if (v_normal.isZeroLength()) { ODA_FAIL(); return; } OdGeVector3d dir = direction; OdGeMatrix3d pToW = OdGeMatrix3d::planeToWorld(v_normal); pToW.invert(); dir.transformBy(pToW); double angle = OdGeVector3d::kXAxis.angleTo(dir, OdGeVector3d::kZAxis); //set rotation, size, normal { OdTvVisualize2PrcTiming t(m_pTimer); OdTvTextDataPtr pText = textId.openAsText(); pText->setRotation(angle); if (m_pTimer) m_pTimer->stop(); double h = upVector.length(); double wh = direction.length(); double w = 1.0; if (h > 0) { w = wh / h; } if (m_pTimer) m_pTimer->start(); pText->setWidthFactor(w); pText->setTextSize(h); pText->setNormal(v_normal); } //text style if (pTextStyle) { OdTvTextStyleDef style; double obAngle = 0.0; if (!OdZero(direction.dotProduct(upVector))) { double ang = direction.angleTo(upVector, direction.crossProduct(upVector)); if (ang < 0 || ang > OdaPI2) { ang = fabs(OdaPI2 - fabs(ang)); } obAngle = OdaPI2 - ang; } OdTvTextStyleId stId = getTvTextStyleId(pTextStyle, &obAngle); if (!stId.isNull()) { OdTvVisualize2PrcTiming t(m_pTimer); style.setTextStyle(stId); OdTvTextDataPtr pText = textId.openAsText(); pText->setTextStyle(style); } else { ODA_ASSERT(false); } } //eo if text style... if (bU || bO || bK) { OdTvVisualize2PrcTiming t(m_pTimer); OdTvTextDataPtr pText = textId.openAsText(); if (bU) { pText->setUnderlined(OdTvTextData::kOn); } if (bO) { pText->setOverlined(OdTvTextData::kOn); } if (bK) { pText->setStriked(OdTvTextData::kOn); } } return; } void OdTvVisualize2PrcGeomCollector::text(const OdGePoint3d& position, const OdGeVector3d& normal, const OdGeVector3d& direction, const OdChar* msg, OdInt32 length, bool raw, const OdGiTextStyle* pStyle) { //apply effective traits at first applyEffectiveTraits(m_effectiveTraits); ODA_ASSERT(!m_tvEntity.isNull()); //prepare data OdGeVector3d u, v; ::odgiCalculateTextBasis(u, v, normal, direction, pStyle->textSize(), pStyle->xScale(), pStyle->obliquingAngle(), pStyle->isBackward(), pStyle->isUpsideDown() ); //call main method textEx(position, u, v, msg, length, raw, ::odgiPrepareTextStyle(pStyle, m_textStyle), nullptr); } void OdTvVisualize2PrcGeomCollector::shell(OdInt32 numVertices, const OdGePoint3d* vertexList, OdInt32 faceListSize, const OdInt32* faceList, const OdGiEdgeData* pEdgeData, const OdGiFaceData* pFaceData, const OdGiVertexData* pVertexData) { //apply effective traits at first applyEffectiveTraits(m_effectiveTraits); ODA_ASSERT(!m_tvEntity.isNull()); bool bFillIn2D = false; bool bSolid = false; bool forceFilledShell = needShellAsColoredArea(m_traits, bFillIn2D, bSolid); if (forceFilledShell) { OdTvGeometryDataId planeColoredAreaId; { OdTvVisualize2PrcTiming t(m_pTimer); if (hasSubGroup()) planeColoredAreaId = m_tvSubGroup.openAsSubGroup()->appendColoredShape(numVertices, vertexList, faceListSize, faceList); else planeColoredAreaId = getCurrentEntityPtr(OdTv::kForWrite)->appendColoredShape(numVertices, vertexList, faceListSize, faceList); setCurrentTargetDisplayMode(planeColoredAreaId); } if (pVertexData && pVertexData->trueColors()) { OdCmEntityColor* pColors = (OdCmEntityColor*)pVertexData->trueColors(); OdTvRGBColorDefArray colors; colors.resize(numVertices); for (OdInt32 i = 0; i < numVertices; i++) { if (pColors[i].colorMethod() != OdCmEntityColor::kByColor) // color can be only rgb { ODA_ASSERT(false); colors[i] = OdTvRGBColorDef(255, 255, 255); } else colors[i] = OdTvRGBColorDef(pColors[i].red(), pColors[i].green(), pColors[i].blue()); } //open plane colored area OdTvVisualize2PrcTiming t(m_pTimer); OdTvColoredShapeDataPtr pColoredShape = planeColoredAreaId.openAsColoredShape(); if (!pColoredShape.isNull()) { pColoredShape->setVertexColors(colors); } } if (pEdgeData && pEdgeData->visibility() != NULL) { OdInt32 nFace = 0; OdInt32 nEdge = 0; getCountShellFacesAndEdges(faceListSize, faceList, nFace, nEdge); OdUInt8* pVisibility = (OdUInt8*)pEdgeData->visibility(); OdTvVisibilityDefArray visibilities; fillVisualizeVisibilitiesArray(nEdge, pVisibility, visibilities, NULL); //open plane colored area OdTvVisualize2PrcTiming t(m_pTimer); OdTvColoredShapeDataPtr pColoredShape = planeColoredAreaId.openAsColoredShape(); if (!pColoredShape.isNull()) { pColoredShape->setEdgesVisibilities(visibilities); } } if ((m_traits.drawFlags() & OdGiSubEntityTraits::kDrawContourFill) != 0) { OdTvColoredShapeDataPtr pColoredShape = planeColoredAreaId.openAsColoredShape(); if (!pColoredShape.isNull()) { pColoredShape->setDrawContour(true); } } { OdTvColoredShapeDataPtr pColoredShape = planeColoredAreaId.openAsColoredShape(); if (!pColoredShape.isNull()) { pColoredShape->setSolid(bSolid); } } return; } OdTvVisualize2PrcTiming t(m_pTimer); // open entity OdTvGeometryDataId shellId; OdTvShellDataPtr pShell; { OdTvVisualize2PrcTiming t(m_pTimer); if (hasSubGroup()) shellId = m_tvSubGroup.openAsSubGroup()->appendShell(numVertices, vertexList, faceListSize, faceList); else shellId = getCurrentEntityPtr(OdTv::kForWrite)->appendShell(numVertices, vertexList, faceListSize, faceList); setCurrentTargetDisplayMode(shellId); //open shell pShell = shellId.openAsShell(); // enable spatial tree if (numVertices > 50000) pShell->setUseSpatialTreeForSelection(true); pShell->setNeedFillIn2D(bFillIn2D); OdTvShellData::FaceCulling culMode = OdTvShellData::kInherited; if (isRenderFrontFaceOnly()) culMode = OdTvShellData::kOn; pShell->setBackFaceCulling(culMode); } if (!pShell.isNull()) { //we suppose that there is no fill pattern in PRC // get information about vertices if (pVertexData != NULL) { //colors if (pVertexData->trueColors() != NULL) { OdCmEntityColor* pColors = (OdCmEntityColor*)pVertexData->trueColors(); OdTvRGBColorDefArray colors; colors.resize(numVertices); for (OdInt32 i = 0; i < numVertices; i++) { if (pColors[i].colorMethod() != OdCmEntityColor::kByColor) // color can be only rgb { ODA_ASSERT(1); colors[i] = OdTvRGBColorDef(0, 0, 0); } else colors[i] = OdTvRGBColorDef(pColors[i].red(), pColors[i].green(), pColors[i].blue()); } OdTvVisualize2PrcTiming t(m_pTimer); pShell->setVertexColorsViaRange(0, colors); } // normals if (pVertexData->normals() != NULL) { OdTvVisualize2PrcTiming t(m_pTimer); pShell->setVertexNormalsViaRange(0, numVertices, pVertexData->normals()); } // orientation if (pVertexData->orientationFlag() != kOdGiNoOrientation) { OdTvVisualize2PrcTiming t(m_pTimer); OdTv::OrientationType orientationType = OdTv::kCounterClockwise; if (pVertexData->orientationFlag() == kOdGiClockwise) orientationType = OdTv::kClockwise; pShell->setVertexOrientation(orientationType); } //texture coordinates if (pVertexData->mappingCoords(OdGiVertexData::kAllChannels)) { const OdGePoint3d* origPts = pVertexData->mappingCoords(OdGiVertexData::kAllChannels); OdTvPoint2dArray pts; pts.resize(numVertices); for (OdUInt32 i = 0; i < (OdUInt32)numVertices; ++i) { pts[i].x = origPts[i].x; //since VisualizeAPI use (0,0) as left-bottom, we have to invert Y axis pts[i].y = 1.0 - origPts[i].y; } pShell->setVertexMappingCoordsViaRange(0, pts); } } // calculate number of faces and edges (if need) OdInt32 nFace = 0; OdInt32 nEdge = 0; if (pFaceData != NULL || pEdgeData != NULL) { getCountShellFacesAndEdges(faceListSize, faceList, nFace, nEdge); } // get information about faces if (pFaceData != NULL) { // colors if (pFaceData->trueColors() != NULL) { OdCmEntityColor* pColors = (OdCmEntityColor*)pFaceData->trueColors(); OdTvColorDefArray colors; fillVisualizeColorsArray(nFace, pColors, colors); { OdTvVisualize2PrcTiming t(m_pTimer); pShell->setFaceColorsViaRange(0, colors); } } //we suppose that 'pFaceData->colors()' will not be used in PRC //normals if (pFaceData->normals() != NULL) { OdTvVisualize2PrcTiming t(m_pTimer); pShell->setFaceNormalsViaRange(0, nFace, pFaceData->normals()); } //visibility if (pFaceData->visibility() != NULL) { OdUInt8* pVisibility = (OdUInt8*)pFaceData->visibility(); OdTvVisibilityDefArray visibilities; fillVisualizeVisibilitiesArray(nFace, pVisibility, visibilities, NULL); { OdTvVisualize2PrcTiming t(m_pTimer); pShell->setFaceVisibilitiesViaRange(0, visibilities); } } //layers (there is no layers in PRC) //materials if (pFaceData->materials() != NULL) { OdTvMaterialDefArray materials; materials.resize(nFace); for (OdUInt32 i = 0; i < (OdUInt32)nFace; ++i) { if (!(pFaceData->materials())[i]) { OdTvMaterialDef mDef; materials[i] = mDef; } else { OdUInt32 color = 0; OdTvMaterialId mId = getTvMaterial((pFaceData->materials())[i], color, true); OdTvMaterialDef mDef; if (!mId.isNull()) mDef.setMaterial(mId); materials[i] = mDef; } } { OdTvVisualize2PrcTiming t(m_pTimer); pShell->setFaceMaterialsViaRange(0, materials); } } //mappers if (pFaceData->mappers() != NULL) { OdTvMapperDefArray mappers; mappers.resize(nFace); for (OdUInt32 i = 0; i < (OdUInt32)nFace; ++i) { OdTvMapperDef mDef; OdGiMapper mapper = (pFaceData->mappers())[i]; mDef.setProjection(convertFromGiMapperProjection(mapper.projection())); mDef.setAutoTransform(convertFromGiMapperAutoTransform(mapper.autoTransform())); mDef.setTransform(mapper.transform()); mappers[i] = mDef; } { OdTvVisualize2PrcTiming t(m_pTimer); pShell->setFaceMappersViaRange(0, mappers); } } //transparency if (pFaceData->transparency()) { OdTvTransparencyDefArray transp; transp.resize(nFace); for (OdUInt32 i = 0; i < (OdUInt32)nFace; ++i) { OdCmTransparency t = (pFaceData->transparency())[i]; if (t.isByAlpha()) transp[i] = OdTvTransparencyDef(1.0 - t.alphaPercent()); else transp[i] = OdTvTransparencyDef(); } { OdTvVisualize2PrcTiming t(m_pTimer); pShell->setFaceTransparencyViaRange(0, transp); } } //Face Fill (we suppose that there is no fill pattern in PRC) } // get information about edges if (pEdgeData != NULL) { //colors if (pEdgeData->trueColors() != NULL) { OdCmEntityColor* pColors = (OdCmEntityColor*)pEdgeData->trueColors(); //here we will use set through list since we want to set the kNone colors OdTvColorDefArray colors; OdInt32Array indEdges; fillVisualizeColorsArray(nEdge, pColors, indEdges, colors); { OdTvVisualize2PrcTiming t(m_pTimer); pShell->setEdgeColorsViaList(indEdges, colors); } } //visibility if (pEdgeData->visibility() != NULL) { OdUInt8* pVisibility = (OdUInt8*)pEdgeData->visibility(); OdTvVisibilityDefArray visibilities; OdInt32Array silhouettes; fillVisualizeVisibilitiesArray(nEdge, pVisibility, visibilities, &silhouettes); { OdTvVisualize2PrcTiming t(m_pTimer); pShell->setEdgeVisibilitiesViaRange(0, visibilities); } } } //Set flag about isolines calculation or about excluding from isolines draw for OdPrcBrepModel or OdPrcPolyBrepModel if (m_bIsFromPRCBrep) { OdUInt32 nEdges = pShell->getEdgesCount(); OdInt32Array edges; edges.resize(nEdges); for (OdUInt32 i = 0; i < nEdges; i++) edges[i] = i; pShell->setIndexesOfSilhouetteEdges(edges); //here also we will force set back face culling pShell->setBackFaceCulling(OdTvShellData::kOn); } else { shellId.openObject()->setTargetDisplayMode(OdTvGeometryData::kEveryWhereExceptIsolines); //here also we will force set back face culling OFF pShell->setBackFaceCulling(OdTvShellData::kOff); } } return; } void OdTvVisualize2PrcGeomCollector::mesh(OdInt32 numRows, OdInt32 numColumns, const OdGePoint3d* vertexList, const OdGiEdgeData* pEdgeData, const OdGiFaceData* pFaceData, const OdGiVertexData* pVertexData) { //apply effective traits at first applyEffectiveTraits(m_effectiveTraits); ODA_ASSERT(!m_tvEntity.isNull()); OdTvVisualize2PrcTiming t(m_pTimer); OdTvGeometryDataId resId; if (hasSubGroup()) resId = m_tvSubGroup.openAsSubGroup()->appendMesh(numRows, numColumns, numRows * numColumns, vertexList); else resId = getCurrentEntityPtr(OdTv::kForWrite)->appendMesh(numRows, numColumns, numRows * numColumns, vertexList); setCurrentTargetDisplayMode(resId); //currently we will ignore face, vertex and edges data return; } void OdTvVisualize2PrcGeomCollector::polypoint(OdInt32 numPoints, const OdGePoint3d* pointList, const OdCmEntityColor* pColors, const OdCmTransparency* pTransparency, const OdGeVector3d* pNormals /*= NULL*/, const OdGsMarker* pSubEntMarkers /*NULL*/, OdInt32 nPointSize /*= 0*/) { ODA_ASSERT(!m_tvEntity.isNull()); //apply effective traits at first applyEffectiveTraits(m_effectiveTraits); OdTvVisualize2PrcTiming t(m_pTimer); OdTvGeometryDataId pointCloudId; if (hasSubGroup()) pointCloudId = m_tvSubGroup.openAsSubGroup()->appendPointCloud(numPoints, pointList); else pointCloudId = getCurrentEntityPtr(OdTv::kForWrite)->appendPointCloud(numPoints, pointList); setCurrentTargetDisplayMode(pointCloudId); OdTvPointCloudDataPtr pPointCloud = pointCloudId.openAsPointCloud(); if (pColors) { OdTvRGBColorDefArray colors; colors.resize(numPoints); for (OdInt32 i = 0; i < numPoints; i++) colors[i].setColor(pColors[i].red(), pColors[i].green(), pColors[i].blue()); pPointCloud->setPointColorsViaRange(0, numPoints, colors.asArrayPtr()); } if (pNormals) pPointCloud->setPointNormalsViaRange(0, numPoints, pNormals); pPointCloud->setPointSize(nPointSize); return; } bool OdTvVisualize2PrcGeomCollector::brep(const OdGiBrep& giBrep) { if (!m_bSupportBreps) return false; OdBrBrep br; if (!giBrep.brep(br)) { ODA_FAIL(); return false; } ODA_ASSERT(!m_tvEntity.isNull()); //apply effective traits at first applyEffectiveTraits(m_effectiveTraits); //add brep to the database OdTvVisualize2PrcTiming t(m_pTimer); OdTvGeometryDataId brepId; if (hasSubGroup()) brepId = m_tvSubGroup.openAsSubGroup()->appendBrep(br, giBrep.database()); else brepId = getCurrentEntityPtr(OdTv::kForWrite)->appendBrep(br, giBrep.database()); if (brepId.isValid()) { OdTvBrepDataPtr pBrep = brepId.openAsBrep(); pBrep->setFacetRes(m_facetResForBrep); pBrep->setEnableCaching(true); OdTvBrepData::FaceCulling culMode = OdTvBrepData::kInherited; if (isRenderFrontFaceOnly()) culMode = OdTvBrepData::kOn; pBrep->setBackFaceCulling(culMode); pBrep->setUsePolyEdgesWithShadedModes(true); } return true; } void OdTvVisualize2PrcGeomCollector::worldLine(const OdGePoint3d points[2]) { ODA_ASSERT(!m_tvEntity.isNull()); //apply effective traits at first applyEffectiveTraits(m_effectiveTraits); //get matrix OdGeMatrix3d mat; if (m_modelTransformStack.top()) mat = m_modelTransformStack.top()->inverse(); else mat.setToIdentity(); OdGePoint3d polyPnts[2]; polyPnts[0] = mat * points[0]; polyPnts[1] = mat * points[1]; polylineEx(2, polyPnts); return; } void OdTvVisualize2PrcGeomCollector::draw(const OdGiDrawable* pDrawable) { bool bRes = pDrawable->worldDraw(this); if (!bRes) pDrawable->viewportDraw(this); return; } OdTvEntityPtr OdTvVisualize2PrcGeomCollector::getCurrentEntityPtr(OdTv::OpenMode mode) { if (!m_pCurrentTvEntity.isNull()) { if (m_nCurrentTvEntityMode == mode) return m_pCurrentTvEntity; else m_pCurrentTvEntity.release(); } OdTvVisualize2PrcTiming t(m_pTimer); m_pCurrentTvEntity = m_tvEntity.openObject(mode); m_nCurrentTvEntityMode = mode; return m_pCurrentTvEntity; } OdTvSubGroupDataPtr OdTvVisualize2PrcGeomCollector::getCurrentSubGroupPtr() { if (!m_pSubGroupData.isNull() || m_tvSubGroup.isNull()) return m_pSubGroupData; OdTvVisualize2PrcTiming t(m_pTimer); m_pSubGroupData = m_tvSubGroup.openAsSubGroup(); return m_pSubGroupData; } OdString OdTvVisualize2PrcGeomCollector::generateUniqName(const OdString& prefix, NameGenerationTypes type) { OdString str; switch (type) { case kMaterialName: str.format(L"_%d", m_uniqNumberMaterial++); break; case kGenericMaterialName: str.format(L"_%d", m_uniqNumberGenericMaterial++); break; case kLinetypeName: str.format(L"_%d", m_uniqNumberLinetype++); break; case kOtherName: default: str.format(L"_%d", m_uniqNumber++); break; } return prefix + str; } OdString OdTvVisualize2PrcGeomCollector::fixFilePath(const OdString& file, OdDbBaseHostAppServices::FindFileHint hint) { OdDbBaseHostAppServices* pAppServ = OdGsDbRootLinkage::getDatabaseDbBaseHostAppServices(m_pPrcContext->database()); if (!pAppServ) return file; OdString fndRes = pAppServ->findFile(file); if (!fndRes.isEmpty()) return file; int fndPos = file.reverseFind(L'\\'); OdString fileName = file; if (fndPos >= 0) { fileName = file.right(file.getLength() - fndPos - 1); } fndRes = pAppServ->findFile(fileName, m_pPrcContext->database(), hint); if (!fndRes.isEmpty()) return fndRes; return file; } void OdTvVisualize2PrcGeomCollector::createNewSubGroup(bool byTransform) { SubGroupTraitsData data = getSubGroupTraitsData(m_effectiveTraits); { if (needApplyTransform() && !m_modelTransformStack.empty()) data.m_mtx = *m_modelTransformStack.top(); if (m_traitsSubGroupMap.find(data) != m_traitsSubGroupMap.end()) { m_tvSubGroup = m_traitsSubGroupMap[data]; m_pSubGroupData.release(); bool bWasSubGroup = hasSubGroup(); m_parentStack.push(OdTvVisualize2PrcParentsOfSubGroupDef(bWasSubGroup ? m_tvSubGroup : OdTvGeometryDataId(), isTraitsValid(), m_traits , isSubGroupDueToTransform(), m_parentObjectId)); if (bWasSubGroup) { m_parentObjectId.m_entId.setNull(); m_parentObjectId.m_subGroupId = m_tvSubGroup; } else { m_parentObjectId.m_subGroupId.setNull(); m_parentObjectId.m_entId = m_tvEntity; } setHasSubGroup(true); return; } } if (byTransform && !isTraitsValid()) { //this if means that current traits is valid (there was no geometries yet) //and, thus, we should apply current traits to the entity bool bApplyTr = needApplyTransform(); setNeedApplyTransform(false); applyEffectiveTraits(m_effectiveTraits); setNeedApplyTransform(bApplyTr); } OdTvEntityPtr entity = getCurrentEntityPtr(OdTv::kForWrite); OdTvSubGroupDataPtr pSubGroup = getCurrentSubGroupPtr(); if (entity.isNull() && pSubGroup.isNull()) return; m_pCurrentTvEntity.release(); m_pSubGroupData.release(); //if a) we need to create subGroup due to the new trait // b) we are already inside the subgroup // c) current subgroup was created NOT due to the transform // we need to perform rollback for the subgroup if (!byTransform && m_parentObjectId.exist() && !isSubGroupDueToTransform()) { rollbackSubGroup(false); // check traits differences again OdUInt32 diff = getTraitsDifference(m_effectiveTraits); if (diff == 0) // we shouldn't create new subgroup return; if (hasSubGroup()) { pSubGroup = getCurrentSubGroupPtr(); m_pSubGroupData.release(); } else { entity = getCurrentEntityPtr(OdTv::kForWrite); m_pCurrentTvEntity.release(); } } bool bWasSubGroup = hasSubGroup(); if (bWasSubGroup) { m_parentStack.push(OdTvVisualize2PrcParentsOfSubGroupDef(m_tvSubGroup, isTraitsValid(), m_traits, isSubGroupDueToTransform(), m_parentObjectId)); } else { m_parentStack.push(OdTvVisualize2PrcParentsOfSubGroupDef(OdTvGeometryDataId(), isTraitsValid(), m_traits, isSubGroupDueToTransform(), m_parentObjectId)); } if (bWasSubGroup) { m_parentObjectId.m_entId.setNull(); m_parentObjectId.m_subGroupId = m_tvSubGroup; } else { m_parentObjectId.m_subGroupId.setNull(); m_parentObjectId.m_entId = m_tvEntity; } { OdTvVisualize2PrcTiming t(m_pTimer); if (hasSubGroup()) m_tvSubGroup = pSubGroup->appendSubGroup(); else m_tvSubGroup = entity->appendSubGroup(); } m_traitsSubGroupMap[data] = m_tvSubGroup; setHasSubGroup(true); setSubGroupDueToTransform(byTransform); return; } void OdTvVisualize2PrcGeomCollector::rollbackSubGroup(bool byTransform) { setTraitsValid(false); if (m_parentStack.empty()) return; if (m_parentStack.top()->subGroupId.isNull()) { setHasSubGroup(false); } else { m_tvSubGroup = m_parentStack.top()->subGroupId; setHasSubGroup(true); } setTraitsValid(m_parentStack.top()->bTraitsValid); m_traits = m_parentStack.top()->traits; m_parentObjectId = m_parentStack.top()->parentObjectId; bool bRolledByTransform = isSubGroupDueToTransform(); bool bTr = m_parentStack.top()->bDueToTransform; setSubGroupDueToTransform(bTr); m_parentStack.pop(); m_pCurrentTvEntity.release(); //bRolledByTransform means we already rollback subEntity with transform //else we have to rollback all subs without transform until first sub with transform; we also have to rollback this sub too. if (byTransform && !bRolledByTransform) { if (hasSubGroup()) rollbackSubGroup(true); } } void OdTvVisualize2PrcGeomCollector::applyEffectiveTraits(const OdGiSubEntityTraitsData& effectiveTraits) { if (m_tvEntity.isNull()) return; OdTvEntityPtr entity = getCurrentEntityPtr(OdTv::kForWrite); OdTvSubGroupDataPtr pSubGroup = getCurrentSubGroupPtr(); if (entity.isNull() && pSubGroup.isNull()) return; if (!isTraitsValid()) { //color: we will catch only normal 'byColor' here if (effectiveTraits.trueColor().isByColor()) { OdTvVisualize2PrcTiming t(m_pTimer); if (hasSubGroup()) pSubGroup->setColor(OdTvColorDef(effectiveTraits.trueColor().red(), effectiveTraits.trueColor().green(), effectiveTraits.trueColor().blue())); else entity->setColor(OdTvColorDef(effectiveTraits.trueColor().red(), effectiveTraits.trueColor().green(), effectiveTraits.trueColor().blue())); } //transparency if (!effectiveTraits.transparency().isByLayer()) { if (effectiveTraits.transparency().isByBlock()) ODA_ASSERT(false); else { double alpha = effectiveTraits.transparency().alphaPercent(); if (!OdZero(1. - alpha)) { OdTvVisualize2PrcTiming t(m_pTimer); OdTvTransparencyDef trDef; trDef.setValue(1. - alpha); if (hasSubGroup()) pSubGroup->setTransparency(trDef); else entity->setTransparency(trDef); } } } //linetype if (effectiveTraits.lineType() ) { OdUInt32 flg = 0; OdTvLinetypeId ltId = getTvLineType(effectiveTraits.lineType(), flg); if (!ltId.isNull()) //we suppose that here we can have only normal linetype (without inheritance) { OdTvVisualize2PrcTiming t(m_pTimer); OdTvLinetypeDef ltDef; ltDef.setLinetype(ltId); if (hasSubGroup()) pSubGroup->setLinetype(ltDef); else entity->setLinetype(ltDef); } } //material if (effectiveTraits.material()) { OdUInt32 color = 0; OdTvMaterialId matId = getTvMaterial(effectiveTraits.material(), color); if (!matId.isNull()) { OdTvVisualize2PrcTiming t(m_pTimer); OdTvMaterialDef mDef; mDef.setMaterial(matId); if (hasSubGroup()) { pSubGroup->setMaterial(mDef); if (color != 0) pSubGroup->setColor(OdTvColorDef(ODGETBLUE(color), ODGETGREEN(color), ODGETRED(color))); } else { entity->setMaterial(mDef); if (color != 0) entity->setColor(OdTvColorDef(ODGETBLUE(color), ODGETGREEN(color), ODGETRED(color))); } } } // else // NEED TO CHECK // { // if (hasSubGroup()) // { // OdTvVisualize2PrcTiming t(m_pTimer); // entity->resetParentMaterial(); // } // } //update traits m_traits = effectiveTraits; setTraitsValid(true); //apply transform if need if (!m_modelTransformStack.empty() && needApplyTransform()) { OdTvVisualize2PrcTiming t(m_pTimer); if (hasSubGroup()) pSubGroup->setModelingMatrix(*m_modelTransformStack.top()); else entity->setModelingMatrix(*m_modelTransformStack.top()); setNeedApplyTransform(false); } } else { OdUInt32 diff = getTraitsDifference(effectiveTraits); if (diff != 0) { ODA_ASSERT(!m_tvEntity.isNull()); { bool bRecheck = m_parentObjectId.exist(); //need create new subgroup due to changes in properties createNewSubGroup(); if (bRecheck) diff = getTraitsDifference(effectiveTraits); } applyTraitsDifference(effectiveTraits, diff); m_traits = effectiveTraits; if (!m_modelTransformStack.empty() && needApplyTransform()) { OdTvVisualize2PrcTiming t(m_pTimer); if (hasSubGroup()) pSubGroup->setModelingMatrix(*m_modelTransformStack.top()); else entity->setModelingMatrix(*m_modelTransformStack.top()); setNeedApplyTransform(false); } setTraitsValid(true); } else if (m_traits.fill() != effectiveTraits.fill()) m_traits.setFill(effectiveTraits.fill()); } return; } OdUInt32 OdTvVisualize2PrcGeomCollector::getTraitsDifference(const OdGiSubEntityTraitsData& t2) { OdUInt32 res = 0; //color if (m_traits.trueColor().isByColor() != t2.trueColor().isByColor()) res |= kDiffColor; if (m_traits.trueColor().isByColor()) { if (m_traits.trueColor() != t2.trueColor()) res |= kDiffColor; } //linetype if (m_traits.lineType() != t2.lineType()) res |= kDiffLineType; //material if (m_traits.material() != t2.material()) res |= kDiffMaterial; //transparency if (m_traits.transparency().isByAlpha() != t2.transparency().isByAlpha()) res |= kDiffTransparency; if (m_traits.transparency().isByAlpha()) { if (m_traits.transparency().alpha() != t2.transparency().alpha()) res |= kDiffTransparency; } return res; } void OdTvVisualize2PrcGeomCollector::applyTraitsDifference(const OdGiSubEntityTraitsData& traits, OdUInt32 diff) { OdTvEntityPtr entity = getCurrentEntityPtr(OdTv::kForWrite); OdTvSubGroupDataPtr pSubGroup = getCurrentSubGroupPtr(); if (entity.isNull() && pSubGroup.isNull()) return; if (diff & kDiffColor) { //color: we will catch only normal 'byColor' here if (traits.trueColor().isByColor()) { OdTvVisualize2PrcTiming t(m_pTimer); if (hasSubGroup()) pSubGroup->setColor(OdTvColorDef(traits.trueColor().red(), traits.trueColor().green(), traits.trueColor().blue())); else entity->setColor(OdTvColorDef(traits.trueColor().red(), traits.trueColor().green(), traits.trueColor().blue())); } else { if (hasSubGroup()) { OdTvVisualize2PrcTiming t(m_pTimer); pSubGroup->setColor(OdTvColorDef(0,0,0)); //black } } } if (diff & kDiffLineType) { if (traits.lineType()) { OdUInt32 flg = 0; OdGiLinetypeTraits* pLTTraits = &(m_pLinetyper->linetypeTraits()); if (pLTTraits) { OdUInt32 flg = 0; OdTvLinetypeId ltId = getTvLineType(traits.lineType(), flg); if (!ltId.isNull()) //we suppose that here we can have only normal linetype (without inheritance) { OdTvVisualize2PrcTiming t(m_pTimer); OdTvLinetypeDef ltDef; ltDef.setLinetype(ltId); if (hasSubGroup()) pSubGroup->setLinetype(ltDef); else entity->setLinetype(ltDef); } } } else { if (hasSubGroup()) { OdTvVisualize2PrcTiming t(m_pTimer); OdTvLinetypeDef ltDef; ltDef.setPredefinedLinetype(OdTvLinetype::kSolid); if (hasSubGroup()) pSubGroup->setLinetype(ltDef); else entity->setLinetype(ltDef); } } } if (diff & kDiffMaterial) { if (traits.material()) { OdUInt32 color = 0; OdTvMaterialId matId = getTvMaterial(traits.material(), color); if (!matId.isNull()) { OdTvVisualize2PrcTiming t(m_pTimer); OdTvMaterialDef mDef; mDef.setMaterial(matId); if (hasSubGroup()) { pSubGroup->setMaterial(mDef); if (color != 0) pSubGroup->setColor(OdTvColorDef(ODGETBLUE(color), ODGETGREEN(color), ODGETRED(color))); } else { entity->setMaterial(mDef); if (color != 0) entity->setColor(OdTvColorDef(ODGETBLUE(color), ODGETGREEN(color), ODGETRED(color))); } } } // else // NEED TO CHECk // { // if (hasSubGroup()) // { // OdTvVisualize2PrcTiming t(m_pTimer); // entity->resetParentMaterial(); // ??? // } // } } if (diff & kDiffTransparency) { OdTvTransparencyDef trDef; if (traits.transparency().isByAlpha()) { //here we will set in any case since it can means reset of the transparency trDef.setValue(1.0 - traits.transparency().alphaPercent()); OdTvVisualize2PrcTiming t(m_pTimer); if (hasSubGroup()) pSubGroup->setTransparency(trDef); else entity->setTransparency(trDef); } else { if (hasSubGroup()) { OdTvVisualize2PrcTiming t(m_pTimer); trDef.setValue(0.); if (hasSubGroup()) pSubGroup->setTransparency(trDef); else entity->setTransparency(trDef); } } } return; } bool isGenericColorMaterial(const OdPrcMaterialGenericPtr& pGeneric) { return pGeneric->getDiffuse() == pGeneric->getAmbient(); } OdTvMaterialId OdTvVisualize2PrcGeomCollector::getTvMaterial(OdDbStub* materialId, OdUInt32& nColor, bool bForceCreate/* = false*/) { if (materialId == NULL) return OdTvMaterialId(); //prepare initially empty result OdTvMaterialId resId; resId.setNull(); //open native prc drawable through the context and filling material properties OdGiDrawablePtr pMat = m_pPrcContext->openDrawable(materialId); if (pMat.isNull()) { ODA_ASSERT(false); return resId; } //we know that here OdGiDrawable should be the PrcCategory1LineStyle OdPrcCategory1LineStylePtr pStyle = OdPrcCategory1LineStyle::cast(pMat); if (pStyle.isNull()) { ODA_ASSERT(false); return resId; } OdUInt32 colorVal = pStyle->getTrueColor().color(); nColor = colorVal; bool bColorMaterial = pStyle->getMaterialID().isNull(); bool bReplaceWithGeneric = false; //try to find already created material if (!bColorMaterial) { auto fnd = m_materialsPrcIdMap.find(pStyle->getMaterialID()); if (fnd != m_materialsPrcIdMap.end()) return fnd->second; // try to find generic material without texture and compare with default parameters OdPrcMaterialPtr pMat = pStyle->getMaterialID().openObject(); if (!pMat.isNull()) { OdPrcMaterialGenericPtr pGeneric; OdPrcTextureApplicationPtr pTxtrApp = OdPrcTextureApplication::cast(pMat.get()); if (!pTxtrApp.isNull()) { OdPrcObjectId genericId = pTxtrApp->getMaterialGenericID(); OdPrcObjectId textureId = pTxtrApp->getTextureDefinitionID(); if (textureId.isNull() && !genericId.isNull()) pGeneric = genericId.openObject(); } else pGeneric = OdPrcMaterialGeneric::cast(pMat.get()); if (!pGeneric.isNull()) { if (isGenericColorMaterial(pGeneric)) nColor = pGeneric->getDiffuse().getTrueColor().color(); else nColor = 0; bReplaceWithGeneric = true; } } } else if (!bForceCreate) bReplaceWithGeneric = true; OdGiMaterialTraitsTaker matTraits; OdUInt32 flags = pMat->setAttributes(&matTraits); //flags now supposed to be unused if (flags & OdGiMaterialTraits::kByBlock) return resId; else if (flags & OdGiMaterialTraits::kByLayer) return resId; OdTvVisualize2PrcTiming t(m_pTimer); if (bReplaceWithGeneric) // check gloss factor in map { GenericMaterialData data = getGenericMaterialData(matTraits, nColor != 0); if (m_genericMaterials.find(data) != m_genericMaterials.end()) return m_genericMaterials[data]; else { OdTvMaterialId resId = createGenericMaterial(data); if (!bColorMaterial) m_materialsPrcIdMap[pStyle->getMaterialID()] = resId; return resId; } } //use protocol extension (if exist) for getting material name OdString strMatName; OdDbBaseMaterialPE* pMaterialPE = OdGsDbRootLinkage::getDbBaseMaterialPE(pMat); if (!pMaterialPE) { OdTvStubToNamesMap::iterator it; if (!bColorMaterial) it = m_generatedNames.find(pStyle->getMaterialID()); else it = m_generatedNames.find(materialId); if (it == m_generatedNames.end()) { strMatName = generateUniqName(m_strNamePrefix + "_Material_", kMaterialName); if (!bColorMaterial) m_generatedNames[pStyle->getMaterialID()] = strMatName; else m_generatedNames[materialId] = strMatName; } else { strMatName = it->second; } } else { strMatName = pMaterialPE->name(pMat); if (!strMatName.isEmpty()) strMatName = m_strNamePrefix + strMatName; } if (strMatName.isEmpty()) { strMatName = m_strNamePrefix + "EmptyMaterialName"; } //create Visualize material OdTvDatabasePtr pDb = m_tvDbId.openObject(OdTv::kForWrite); resId = createTvMaterial(strMatName, pDb); if (resId.isNull()) { ODA_ASSERT(false); return resId; } if (!bColorMaterial) m_materialsPrcIdMap[pStyle->getMaterialID()] = resId; //fill Visualize material properties OdTvMaterialPtr resMat = resId.openObject(OdTv::kForWrite); setObjectUserData< OdTvMaterialPtr >(resMat, materialId); OdTvMaterialColor matAmbientColor, matDiffuseColor, matSpecularColor, matEmissionColor; OdTvColorDef tvAmbientColor, tvDiffuseColor, tvSpecularColor, tvEmissionColor, tvColor; OdGiMaterialColor giAmbientColor, giDiffuseColor, giSpecularColor, giEmissionColor, giColor; OdGiMaterialMap giMatMap, giMatDiffuseMap, giMatEmissionMap, giMatOpacityMap, giMatBumpMap; OdTvMaterialMap tvMatDiffuseMap, tvMatEmissionMap, tvMatOpacityMap, tvMatBumpMap; OdInt16 mapperProjDiffuse, mapperProjEmission, mapperProjOpacity, mapperProjBump; OdInt16 mapperAutoTrDiffuse, mapperAutoTrEmission, mapperAutoTrOpacity, mapperAutoTrBump; matTraits.ambient(giAmbientColor); tvAmbientColor = getTvColorFromDbColor(giAmbientColor.color()); matAmbientColor.setColor(tvAmbientColor); matAmbientColor.setFactor(giAmbientColor.factor()); matAmbientColor.setMethod((OdTvMaterialColor::Method)giAmbientColor.method()); matTraits.diffuse(giDiffuseColor, giMatDiffuseMap); tvDiffuseColor = getTvColorFromDbColor(giDiffuseColor.color()); matDiffuseColor.setColor(tvDiffuseColor); matDiffuseColor.setFactor(giDiffuseColor.factor()); matDiffuseColor.setMethod((OdTvMaterialColor::Method)giDiffuseColor.method()); getOdTvMaterialMapFromOdGiMaterialMap(giMatDiffuseMap, tvMatDiffuseMap, mapperProjDiffuse, mapperAutoTrDiffuse); double glossFactor = 0.; matTraits.specular(giSpecularColor, giMatMap, glossFactor); tvSpecularColor = getTvColorFromDbColor(giSpecularColor.color()); matSpecularColor.setColor(tvSpecularColor); matSpecularColor.setFactor(giSpecularColor.factor()); matSpecularColor.setMethod((OdTvMaterialColor::Method)giSpecularColor.method()); //specular override double specularOverride = matTraits.specularHighlightingOverride(); matTraits.emission(giEmissionColor, giMatEmissionMap); tvEmissionColor = getTvColorFromDbColor(giEmissionColor.color()); matEmissionColor.setColor(tvEmissionColor); matEmissionColor.setFactor(giEmissionColor.factor()); matEmissionColor.setMethod((OdTvMaterialColor::Method)giEmissionColor.method()); getOdTvMaterialMapFromOdGiMaterialMap(giMatEmissionMap, tvMatEmissionMap, mapperProjEmission, mapperAutoTrEmission); double opas; matTraits.opacity(opas, giMatOpacityMap); getOdTvMaterialMapFromOdGiMaterialMap(giMatOpacityMap, tvMatOpacityMap, mapperProjOpacity, mapperAutoTrOpacity); matTraits.bump(giMatBumpMap); getOdTvMaterialMapFromOdGiMaterialMap(giMatBumpMap, tvMatBumpMap, mapperProjBump, mapperAutoTrBump); OdGiMaterialColor tintColor; bool bUseTint = GETBIT(matTraits.channelFlags(), OdGiMaterialTraits::kUseTint); matTraits.tint(tintColor); OdTvMaterialColor tvTintColor = getTvColorFromDbColor(tintColor.color()); //prepare stream with user data if (mapperProjDiffuse != 1 || mapperAutoTrDiffuse != 1) { OdInt16 verStream = 1; OdStreamBufPtr pStreamBuff = OdMemoryStream::createNew(); OdPlatformStreamer::wrInt16(*pStreamBuff, verStream); OdPlatformStreamer::wrInt16(*pStreamBuff, mapperProjDiffuse); OdPlatformStreamer::wrInt16(*pStreamBuff, mapperProjOpacity); OdPlatformStreamer::wrInt16(*pStreamBuff, mapperProjBump); OdPlatformStreamer::wrInt16(*pStreamBuff, mapperAutoTrDiffuse); OdPlatformStreamer::wrInt16(*pStreamBuff, mapperAutoTrOpacity); OdPlatformStreamer::wrInt16(*pStreamBuff, mapperAutoTrBump); pStreamBuff->rewind(); OdUInt8Array buffer; buffer.resize((OdUInt8Array::size_type)pStreamBuff->length()); pStreamBuff->getBytes(buffer.asArrayPtr(), (OdUInt8Array::size_type)pStreamBuff->length()); // Add user data bool alreadyExist = false; OdString regAppName = L"ExGsVisualizeDevice_MATERIAL"; OdTvRegAppId appId = pDb->registerAppName(regAppName, alreadyExist); OdTvByteUserData* pDbUserData = new OdTvByteUserData(buffer.asArrayPtr(), (OdUInt8Array::size_type)pStreamBuff->length(), OdTvByteUserData::kCopyOwn, true); resMat->appendUserData(pDbUserData, appId); } // Set properties to new tv material resMat->setAmbient(matAmbientColor); resMat->setDiffuse(matDiffuseColor, tvMatDiffuseMap); resMat->setSpecular(matSpecularColor, glossFactor); if (OdNonZero(specularOverride)) resMat->setUseVisualStyleSpecular(specularOverride < 0. ? OdTvMaterial::kUseVisualStyleSpecular : OdTvMaterial::kOverride, specularOverride < 0. ? -specularOverride : specularOverride); resMat->setEmission(matEmissionColor, tvMatEmissionMap); resMat->setOpacity(opas, &tvMatOpacityMap); resMat->setBump(tvMatBumpMap); matTraits.shadingAmbient(giColor); tvColor = getTvColorFromDbColor(giColor.color()); resMat->setSecondaryAmbient(tvColor); matTraits.shadingDiffuse(giColor); tvColor = getTvColorFromDbColor(giColor.color()); resMat->setSecondaryDiffuse(tvColor); matTraits.shadingSpecular(giColor); tvColor = getTvColorFromDbColor(giColor.color()); resMat->setSecondarySpecular(tvColor); matTraits.shadingOpacity(opas); resMat->setSecondaryOpacity(opas); resMat->setSupportNonTextureMode(matTraits.diffuseColorMode() != OdGiMaterialTraits::kDiffuseRealisticColor); resMat->setTint(tvTintColor, bUseTint); return resId; } OdTvLinetypeId OdTvVisualize2PrcGeomCollector::getTvLineType(OdDbStub* linetypeId, OdUInt32& flg) { OdGiLinetypeTraits* pLTTraits = &(m_pLinetyper->linetypeTraits()); if (pLTTraits == nullptr) return OdTvLinetypeId(); if (linetypeId == nullptr) return OdTvLinetypeId(); //prepare initially empty result OdTvLinetypeId resId; resId.setNull(); //open native prc drawable through the context and filling material properties OdGiDrawablePtr pLT = m_pPrcContext->openDrawable(linetypeId); if (pLT.isNull()) { ODA_ASSERT(false); return resId; } //we know that here OdGiDrawable should be the PrcCategory1LineStyle OdPrcCategory1LineStylePtr pStyle = OdPrcCategory1LineStyle::cast(pLT); if (pStyle.isNull()) { ODA_ASSERT(false); return resId; } if (pStyle->getLinePatternID().isNull()) return resId; //try to find already created linetype OdTvStubToLinetypeMap::iterator fnd = m_lineTypesMap.find(pStyle->getLinePatternID()); if (fnd != m_lineTypesMap.end()) resId = fnd->second; if (!resId.isNull()) return resId; //temporarry set nnot zero scale with purpose to get an additional scale from linetype double oldScale = pLTTraits->scale(); if (OdZero(oldScale)) pLTTraits->setScale(1.0); OdUInt32 flags = pLT->setAttributes(pLTTraits); //restore linetype scale double lineTypeScale; if (OdZero(oldScale)) lineTypeScale = 1.0 / pLTTraits->scale(); else lineTypeScale = oldScale / pLTTraits->scale(); if (OdZero(oldScale)) pLTTraits->setScale(oldScale); //flags now supposed to be unused if (flags & OdGiLinetypeTraits::kContinuous) { flg = OdGiLinetypeTraits::kContinuous; return resId; } else if (flags & OdGiLinetypeTraits::kByBlock) { flg = OdGiLinetypeTraits::kByBlock; return resId; } else if (flags & OdGiLinetypeTraits::kByLayer) { flg = OdGiLinetypeTraits::kByLayer; return resId; } //specific traits for prc linetype (in opposite case we will have call 'linetypeGenerationCriteria' // which will lead to muticache for each view) OdGiLinetypeDashArray dashes; pLTTraits->dashes(dashes); if (dashes.size() == 2) { if (Od_abs(dashes[0].length) > 9e5 || Od_abs(dashes[1].length) < 1e-5) { flg = OdGiLinetypeTraits::kContinuous; return resId; } } //use protocol extension (if exist) for getting material name OdString strLineTypeName; OdDbBaseLinetypePE* pLinetypePE = OdGsDbRootLinkage::getDbBaseLinetypePE(pLT); if (pLinetypePE) { strLineTypeName = pLinetypePE->name(pLT); if (!strLineTypeName.isEmpty()) { while (strLineTypeName[0] == '*' && !strLineTypeName.isEmpty()) { strLineTypeName = strLineTypeName.right(strLineTypeName.getLength() - 1); } strLineTypeName = m_strNamePrefix + strLineTypeName; } } if (strLineTypeName.isEmpty()) { OdTvStubToNamesMap::iterator it = m_generatedNames.find(pStyle->getLinePatternID()); if (it == m_generatedNames.end()) { strLineTypeName = generateUniqName(m_strNamePrefix + "_LineType_", kLinetypeName); m_generatedNames[pStyle->getLinePatternID()] = strLineTypeName; } else { strLineTypeName = it->second; } } //create Visualize line ype OdTvVisualize2PrcTiming t(m_pTimer); OdTvDatabasePtr pDb = m_tvDbId.openObject(OdTv::kForWrite); OdTvLinetypeElementArray elArray; for (OdUInt32 i = 0; i < dashes.size(); ++i) { OdGiLinetypeDash d = dashes[i]; if (d.isEmbeddedShape()) { OdTvLinetypeShapeElementPtr pEl = OdTvLinetypeShapeElement::createObject(); pEl->setSourceNumber(d.shapeNumber); pEl->setOffset(OdTvVector2d(d.shapeOffset.x, d.shapeOffset.y)); pEl->setRotation(d.shapeRotation); pEl->setScale(d.shapeScale); pEl->setSize(d.length); pEl->setUpright(d.isRotationUpright()); pEl->setUcsOriented(d.isRotationAbsolute()); { OdGiDrawablePtr style = m_pPrcContext->openDrawable(d.styleId); if (!style.isNull()) { OdGiTextStyleTraitsPtr pTr = OdTvVisualize2PrcTextStyleTraitsTaker::createObject(); style->setAttributes(pTr); OdGiTextStyle ts; pTr->textStyle(ts); OdTvTextStyleId stId = getTvTextStyleId(&ts); if (stId.isNull()) { ODA_ASSERT(false); } else { pEl->setStyle(stId); } } } elArray.push_back(pEl); } else if (d.isEmbeddedTextString()) { OdTvLinetypeTextElementPtr pEl = OdTvLinetypeTextElement::createObject(); pEl->setOffset(OdTvVector2d(d.shapeOffset.x, d.shapeOffset.y)); pEl->setRotation(d.shapeRotation); pEl->setScale(d.shapeScale); pEl->setSize((d.length)); pEl->setText(d.textString); pEl->setUpright(d.isRotationUpright()); pEl->setUcsOriented(d.isRotationAbsolute()); { OdGiDrawablePtr style = m_pPrcContext->openDrawable(d.styleId); if (!style.isNull()) { OdGiTextStyleTraitsPtr pTr = OdTvVisualize2PrcTextStyleTraitsTaker::createObject(); style->setAttributes(pTr); OdGiTextStyle ts; pTr->textStyle(ts); OdTvTextStyleId stId = getTvTextStyleId(&ts); if (stId.isNull()) { ODA_ASSERT(false); } else { pEl->setStyle(stId); } } } elArray.push_back(pEl); } else if (Od_abs(d.length) < 1e-8) { OdTvLinetypeDotElementPtr pEl = OdTvLinetypeDotElement::createObject(); elArray.push_back(pEl); } else if (d.length > 0) { OdTvLinetypeDashElementPtr pEl = OdTvLinetypeDashElement::createObject(); pEl->setSize(d.length); elArray.push_back(pEl); } else { OdTvLinetypeSpaceElementPtr pEl = OdTvLinetypeSpaceElement::createObject(); pEl->setSize(-1.0 * d.length); elArray.push_back(pEl); } } resId = createTvLinetype(strLineTypeName, elArray, pDb); //set linetype scale (from object itslef, not from traits) if (!OdEqual(lineTypeScale, 1.)) { OdTvLinetypePtr pLineType = resId.openObject(OdTv::kForWrite); pLineType->setScale(lineTypeScale); } setObjectUserData< OdTvLinetypePtr >(resId.openObject(OdTv::kForWrite), pStyle->getLinePatternID()); m_lineTypesMap[pStyle->getLinePatternID()] = resId; return resId; } OdTvRasterImageId OdTvVisualize2PrcGeomCollector::getTvImageId(const OdGiRasterImage* pImg) { if (pImg == NULL) return OdTvRasterImageId(); OdTvVisualize2PrcTiming t(m_pTimer); OdTvDatabasePtr pTvDb = m_tvDbId.openObject(OdTv::kForWrite); OdString str = pImg->sourceFileName(); OdTvStringToRasterImageMap::iterator fnd = m_rasterImagesMap.find(str); if (fnd != m_rasterImagesMap.end()) return fnd->second; OdString origName = str; if (str.isEmpty()) { str = generateUniqName(L"GeneratedImageName_"); } str = m_strNamePrefix + str; OdTvRasterImageId imgId; if (pImg->scanLineSize() == 0) { ODA_ASSERT(false); return imgId; } if (origName.isEmpty()) { imgId = findUnnamedImage(pImg); if (!imgId.isNull()) return imgId; //allow keepeng generated image in cache origName = str; } OdTvRasterImage::Format fmt = OdTvRasterImage::kRGB; OdGiRasterImage::tagPixelFormatInfo pInf = pImg->pixelFormat(); if (pInf.isRGB()) { fmt = OdTvRasterImage::kRGB; } else if (pInf.isRGBA()) { fmt = OdTvRasterImage::kRGBA; } else if (pInf.isBGR()) { fmt = OdTvRasterImage::kBGR; } else if (pInf.isBGRA()) { fmt = OdTvRasterImage::kBGRA; } else { //Unsupported format ODA_ASSERT(false); return imgId; } OdUInt8* buffer = new OdUInt8[pImg->pixelHeight() * pImg->scanLineSize()]; pImg->scanLines(buffer, 0, pImg->pixelHeight()); if (pImg->numColors() == 0) { imgId = pTvDb->createRasterImage(str, fmt, pImg->pixelWidth(), pImg->pixelHeight(), buffer, pImg->scanLinesAlignment()); } else if (pImg->numColors() == 2 && pImg->colorDepth() == 1) { ODCOLORREF color1 = pImg->color(0); ODCOLORREF color2 = pImg->color(1); bool bInverted = false; if (30 * ODGETRED(color1) + 59 * ODGETGREEN(color1) + 11 * ODGETBLUE(color1) > 30 * ODGETRED(color2) + 59 * ODGETGREEN(color2) + 11 * ODGETBLUE(color2)) { bInverted = false; } else { bInverted = true; } imgId = pTvDb->createRasterImage(str, pImg->pixelWidth(), pImg->pixelHeight(), buffer, bInverted, pImg->scanLinesAlignment()); } else { OdUInt8* paletteBuffer = new OdUInt8[pImg->paletteDataSize()]; pImg->paletteData(paletteBuffer); OdTvRasterImage::BitPerIndex bpi = OdTvRasterImage::kEightBits; if (pImg->colorDepth() != 8) { bpi = OdTvRasterImage::kFourBits; } imgId = pTvDb->createRasterImage(str, fmt, pImg->paletteDataSize(), paletteBuffer, bpi, pImg->pixelWidth(), pImg->pixelHeight(), buffer, pImg->scanLinesAlignment()); delete[] paletteBuffer; } delete[] buffer; if (!imgId.isNull() && !origName.isEmpty()) m_rasterImagesMap[origName] = imgId; return imgId; } OdTvTextStyleId OdTvVisualize2PrcGeomCollector::getTvTextStyleId(const OdGiTextStyle* style, double* pObliquingAngle) { if (style == NULL) return OdTvTextStyleId(); OdString str = style->styleName(); if (str.isEmpty()) { str = style->ttfdescriptor().fileName(); if (str.isEmpty()) { str = m_strNamePrefix + L"NoNameTextStyle"; } else { str = m_strNamePrefix + str; } } else { str = m_strNamePrefix + str; } OdTvVisualize2PrcTextStyleCacheData data; OdString typeface = L"Verdana"; int charset = 0; int family = 34; bool bold = false; bool italic = false; style->font(typeface, bold, italic, charset, family); data.m_name = str; data.m_typeface = typeface; data.m_charset = charset; data.m_family = family; data.setItalic(italic); data.setBold(bold); data.m_fileName = style->ttfdescriptor().fileName(); data.m_dObliquingAngle = (pObliquingAngle) ? *pObliquingAngle : 0.0; //try to find text style in the cache OdTvTextStyleCacheToTextStyleMap::iterator fnd = m_textStyleMap.find(data); if (fnd != m_textStyleMap.end()) return fnd->second; OdTvVisualize2PrcTiming t(m_pTimer); OdTvDatabasePtr pTvDb = m_tvDbId.openObject(OdTv::kForWrite); OdTvTextStyleId textStyle; textStyle = createTvTextStyle(str, pTvDb); if (textStyle.isNull()) return textStyle; OdTvTextStylePtr pTextStyle = textStyle.openObject(OdTv::kForWrite); pTextStyle->setAlignmentMode(OdTvTextStyle::kLeft); pTextStyle->setFont(typeface, bold, italic, charset, family); pTextStyle->setShapeStatus(style->isShape()); pTextStyle->setTextSize(style->textSize() > 0 ? style->textSize() : 1.0); pTextStyle->setWidthFactor(style->xScale()); if (typeface.isEmpty()) pTextStyle->setFileName(style->ttfdescriptor().fileName()); if (!style->bigFontFileName().isEmpty()) { pTextStyle->setBigFontFileName(style->bigFontFileName()); OdString strCustFontFolder = m_strCustomFolder; if (!strCustFontFolder.isEmpty()) pTextStyle->setCustomFontFolder(strCustFontFolder); } if (style->isShape()) { pTextStyle->setShapeStatus(style->isShapeLoaded()); } OdString fileName = style->ttfdescriptor().fileName(); if (fileName.isEmpty()) { OdDbBaseDatabase* pDb = m_pPrcContext->database(); OdDbBaseHostAppServices* pAppServ = OdGsDbRootLinkage::getDatabaseDbBaseHostAppServices(pDb); if (pAppServ) { pAppServ->ttfFileNameByDescriptor(style->ttfdescriptor(), fileName); } } if (!fileName.isEmpty()) { bool alreadyExist = false; OdTvRegAppId regAppId = pTvDb->registerAppName(OD_T("ExGsVisualizeDevice_TEXTSTYLEFONT"), alreadyExist); const OdChar* pStr = fileName.c_str(); //transfer to UTF-8 OdAnsiString sAnsiUtf8(pStr, CP_UTF_8); const char* pUtf8Str = sAnsiUtf8.c_str(); int size = sAnsiUtf8.getLength() + 1; //+1 for the trailing zero // create user data OdTvByteUserData* data = new OdTvByteUserData((void*)pUtf8Str, size, OdTvByteUserData::kCopyOwn, true); pTextStyle->appendUserData(data, regAppId); } if (pObliquingAngle) { pTextStyle->setObliquingAngle(*pObliquingAngle); } pTextStyle->setVertical(style->isVertical()); m_textStyleMap[data] = textStyle; return textStyle; } OdTvMaterialId OdTvVisualize2PrcGeomCollector::createTvMaterial(const OdString& name, OdTvDatabasePtr pDb) { OdTvMaterialId id; if (pDb.isNull()) return id; OdTvResult rc; id = pDb->createMaterial(name, &rc); if (rc == tvOk) return id; OdUInt32 i = 0; OdString str = name + L"_Copy"; if (rc == tvInvalidName) str = m_strNamePrefix + L"Material"; while (rc != tvOk && i++ < m_nNameAttempts) { OdString newName = generateUniqName(str, kMaterialName); id = pDb->createMaterial(newName, &rc); } return id; } OdTvLinetypeId OdTvVisualize2PrcGeomCollector::createTvLinetype(const OdString& name, const OdTvLinetypeElementArray& elements, OdTvDatabasePtr pDb) { OdTvLinetypeId id; if (pDb.isNull()) return id; OdTvResult rc; id = pDb->createLinetype(name, elements, &rc); if (rc == tvOk) return id; OdUInt32 i = 0; OdString str = name; if (rc == tvInvalidName) str = m_strNamePrefix + L"GeneratedLinetype"; while (rc != tvOk && i++ < m_nNameAttempts) { OdString newName = generateUniqName(str, kLinetypeName); id = pDb->createLinetype(name, elements, &rc); } return id; } OdTvTextStyleId OdTvVisualize2PrcGeomCollector::createTvTextStyle(const OdString& name, OdTvDatabasePtr pDb) { OdTvTextStyleId id; if (pDb.isNull()) return id; OdTvResult rc; id = pDb->createTextStyle(name, &rc); if (rc == tvOk) return id; OdUInt32 i = 0; if (rc == tvForbiddenName) { OdString str = m_strNamePrefix + OdString(L"TextStyle_") + name; id = pDb->findTextStyle(str); if (!id.isNull()) { while (rc != tvOk && i++ < m_nNameAttempts) { OdString newName = generateUniqName(str); id = pDb->createTextStyle(newName, &rc); } return id; } id = pDb->createTextStyle(str, &rc); if (rc == tvOk) return id; } OdString str = name + L"_Copy"; if (rc == tvInvalidName) { str = m_strNamePrefix + L"GeneratedTextStyle"; } while (rc != tvOk && i++ < m_nNameAttempts) { OdString newName = generateUniqName(str); id = pDb->createTextStyle(newName, &rc); } return id; } void OdTvVisualize2PrcGeomCollector::getOdTvMaterialMapFromOdGiMaterialMap(const OdGiMaterialMap& giMatMap, OdTvMaterialMap& tvMatMap, OdInt16& mapperProj, OdInt16& mapperAutoTrans) { tvMatMap.setBlendFactor(giMatMap.blendFactor()); OdString textureFilePath = giMatMap.sourceFileName(); if (!textureFilePath.isEmpty()) { textureFilePath = fixFilePath(giMatMap.sourceFileName(), OdDbBaseHostAppServices::kEmbeddedImageFile); } tvMatMap.setSourceFileName(textureFilePath); const OdGiMaterialTexturePtr pTex = giMatMap.texture(); if (!pTex.isNull()) { const OdGiRasterImageTexturePtr texPtr = OdGiRasterImageTexture::cast(pTex); if (!texPtr.isNull() && texPtr->rasterImage()) { OdTvRasterImageId imgId = getTvImageId(texPtr->rasterImage()); if (!imgId.isNull()) { tvMatMap.setSourceRasterImage(imgId); } } else if (giMatMap.source() == OdGiMaterialMap::kProcedural) { OdGiMaterialTextureEntryPtr pEntry = OdGiMaterialTextureEntry::createObject(); OdGiMaterialTextureData::DevDataVariant devData; pEntry->setGiMaterialTexture(devData, OdGiMaterialTextureData::defaultTextureDataImplementationDesc(), *(m_pPrcContext.get()), pTex); OdGiMaterialTextureDataPtr pTexData = pEntry->textureData(); if (!pTexData.isNull()) { OdUInt32 w, h; OdGiPixelBGRA32Array pixels; pTexData->textureData(pixels, w, h); OdGiImageBGRA32 img(w, h, pixels.asArrayPtr()); OdGiRasterImagePtr pImg = OdGiRasterImageBGRA32::createObject(&img); if (!pImg.isNull()) { OdTvRasterImageId imgId = getTvImageId(pImg); if (!imgId.isNull()) { tvMatMap.setSourceRasterImage(imgId); } } } } } const OdGiMapper& difMapper = giMatMap.mapper(); OdTvTextureMapper tvDiffMapper; tvDiffMapper.setUTiling((OdTvTextureMapper::Tiling)(difMapper.uTiling())); tvDiffMapper.setVTiling((OdTvTextureMapper::Tiling)(difMapper.vTiling())); tvDiffMapper.setTransform(difMapper.transform()); tvMatMap.setMapper(tvDiffMapper); mapperProj = (OdInt16)difMapper.projection(); mapperAutoTrans = (OdInt16)difMapper.autoTransform(); return; } OdTvRasterImageId OdTvVisualize2PrcGeomCollector::findUnnamedImage(const OdGiRasterImage* pImg) { OdTvRasterImageId res; if (!pImg) return res; OdArray< OdUInt8 > imgArray; OdUInt32 bufferSZ = pImg->pixelHeight() * pImg->scanLineSize(); imgArray.resize(bufferSZ); OdUInt8* imgBuffer = imgArray.asArrayPtr(); pImg->scanLines(imgBuffer, 0, pImg->pixelHeight()); OdTvStringToRasterImageMap::iterator it = m_rasterImagesMap.begin(); for (; it != m_rasterImagesMap.end(); ++it) { OdTvRasterImageId imgId = it->second; OdTvRasterImagePtr pTvImg = imgId.openObject(OdTv::kForRead); if (pTvImg.isNull()) continue; if (pTvImg->getType() != OdTvRasterImage::kBinary) continue; OdTvVector2d sz = pTvImg->getSize(); if (sz.x != pImg->pixelWidth() || sz.y != pImg->pixelHeight()) continue; OdGiRasterImage::tagPixelFormatInfo pInf = pImg->pixelFormat(); OdTvRasterImage::Format fmt = OdTvRasterImage::kRGBA; if (pInf.isRGB()) { fmt = OdTvRasterImage::kRGB; } else if (pInf.isRGBA()) { fmt = OdTvRasterImage::kRGBA; } else if (pInf.isBGR()) { fmt = OdTvRasterImage::kBGR; } else if (pInf.isBGRA()) { fmt = OdTvRasterImage::kBGRA; } else { continue; } if (fmt != pTvImg->getFormat()) continue; const OdUInt8* pTvImgData = pTvImg->getBinaryData(); if (memcmp(pTvImgData, imgBuffer, bufferSZ) == 0) { res = it->second; break; } } return res; } bool OdTvVisualize2PrcGeomCollector::isRenderFrontFaceOnly() const { if (!isTraitsValid()) return false; if (m_traits.drawFlags() & OdGiSubEntityTraits::kDrawBackfaces) return false; return ((m_traits.drawFlags() & OdGiSubEntityTraits::kDrawFrontfacesOnly) != 0); } void OdTvVisualize2PrcGeomCollector::setCurrentTargetDisplayMode(const OdTvGeometryDataId& id) { if (m_tvEntity.isNull()) return; OdTvResult rc; OdTvGeometryDataPtr geom = id.openObject(&rc); if (geom.isNull() || rc != tvOk) return; geom->setTargetDisplayMode(m_tvTargetDisplayMode); return; } bool OdTvVisualize2PrcGeomCollector::needShellAsColoredArea(const OdGiSubEntityTraitsData& traits, bool& bFillIn2D, bool& bSolid) { bFillIn2D = false; bSolid = false; OdGiSubEntityTraitsData ctxTraits = m_effectiveTraits; OdUInt32 drawFlags = traits.drawFlags(); if (GETBIT(drawFlags, OdGiSubEntityTraits::kDrawContourFill | OdGiSubEntityTraits::kDrawPolygonFill | OdGiSubEntityTraits::kPolygonProcessing)) { bSolid = false; if (GETBIT(drawFlags, OdGiSubEntityTraits::kDrawContourFill | OdGiSubEntityTraits::kDrawPolygonFill)) { return (ctxTraits.fillType() == kOdGiFillAlways); } } if (GETBIT(drawFlags, OdGiSubEntityTraits::kDrawGradientFill | OdGiSubEntityTraits::kDrawSolidFill)) { bSolid = true; return (ctxTraits.fillType() == kOdGiFillAlways); } if (m_renderMode == OdGsView::kHiddenLine) { bFillIn2D = !GETBIT(drawFlags, OdGiSubEntityTraits::kDrawSolidFill); } else bFillIn2D = traits.fillType() == kOdGiFillAlways; return false; } bool OdTvVisualize2PrcGeomCollector::needForceFill(const OdGiSubEntityTraitsData& traits) { OdGiSubEntityTraitsData ctxTraits = m_effectiveTraits; OdUInt32 drawFlags = traits.drawFlags(); if (GETBIT(drawFlags, OdGiSubEntityTraits::kDrawContourFill | OdGiSubEntityTraits::kDrawPolygonFill)) { return (ctxTraits.fillType() == kOdGiFillAlways); } else { if (ctxTraits.fillType() == kOdGiFillAlways) { //here we suppose that GETBIT(m_simplFlags, kSimplFillModeDisabled) == false, thus immediate return true return true; } return false; } if (ctxTraits.fillType() == kOdGiFillAlways) { return true; } return false; } OdUInt8 OdTvVisualize2PrcGeomCollector::getSpecificFillingMode(const OdGiSubEntityTraitsData& traits) { OdUInt8 res = 0; if (GETBIT(traits.drawFlags(), OdGiSubEntityTraits::kDrawSolidFill)) return (OdUInt8)OdTv::kEveryWhere; if (traits.fillType() == kOdGiFillAlways) { res = OdTv::kAsSolid; //eual to call useFillPlane() for vectorizer (we suppose that 'kIgnoreFillPlane' is not set) if (m_bFillPlaneSet) res = OdTv::kAs2D; } return res; } SubGroupTraitsData OdTvVisualize2PrcGeomCollector::getSubGroupTraitsData(const OdGiSubEntityTraitsData& effectiveTraits) { SubGroupTraitsData data; data.m_nColor = effectiveTraits.trueColor().color(); data.m_dTransparency = 1. - effectiveTraits.transparency().alphaPercent(); OdUInt32 flg = 0; OdTvLinetypeId ltId = getTvLineType(effectiveTraits.lineType(), flg); if (!ltId.isNull()) data.m_linetypeHandle = ltId.openObject()->getDatabaseHandle(); OdUInt32 color = 0; OdTvMaterialId matId = getTvMaterial(effectiveTraits.material(), color); if (!matId.isNull()) { data.m_materialHandle = matId.openObject()->getDatabaseHandle(); if (color != 0) data.m_nColor = color; } return data; } OdTvMaterialColor::Method giMatColorMethod2Tv(OdUInt8 nMethod) { OdGiMaterialColor::Method giMethod = static_cast(nMethod); if (giMethod == OdGiMaterialColor::kOverride) return OdTvMaterialColor::kOverride; return OdTvMaterialColor::kInherit; } OdTvMaterialId OdTvVisualize2PrcGeomCollector::createGenericMaterial(const GenericMaterialData& data) { OdTvDatabasePtr pDb = m_tvDbId.openObject(OdTv::kForWrite); OdString strMatName = generateUniqName(m_strNamePrefix + OD_T("_Generic_"), kGenericMaterialName); OdTvMaterialId resId = createTvMaterial(strMatName, pDb); OdTvMaterialPtr pMat = resId.openObject(OdTv::kForWrite); OdTvMaterialColor color; OdTvMaterialMap map; color.setMethod(giMatColorMethod2Tv(data.m_nAmbientMethod)); color.setColor(OdTvColorDef(ODGETBLUE(data.m_nAmbientColor), ODGETGREEN(data.m_nAmbientColor), ODGETRED(data.m_nAmbientColor))); pMat->setAmbient(color); color.setMethod(giMatColorMethod2Tv(data.m_nDiffuseMethod)); color.setColor(OdTvColorDef(ODGETBLUE(data.m_nDiffuseColor), ODGETGREEN(data.m_nDiffuseColor), ODGETRED(data.m_nDiffuseColor))); pMat->setDiffuse(color, map); color.setMethod(giMatColorMethod2Tv(data.m_nEmisisonMethod)); color.setColor(OdTvColorDef(ODGETBLUE(data.m_nEmisionColor), ODGETGREEN(data.m_nEmisionColor), ODGETRED(data.m_nEmisionColor))); pMat->setEmission(color, map); OdTvMaterialColor::Method tvMethod = giMatColorMethod2Tv(data.m_nSpecularMethod); if (tvMethod == OdTvMaterialColor::kInherit) { color.setMethod(OdTvMaterialColor::kOverride); color.setColor(OdTvColorDef(208, 208, 228)); } else { color.setMethod(tvMethod); color.setColor(OdTvColorDef(ODGETBLUE(data.m_nSpecularColor), ODGETGREEN(data.m_nSpecularColor), ODGETRED(data.m_nSpecularColor))); } pMat->setSpecular(color, data.m_dGlossFactor); // add to map m_genericMaterials[data] = resId; return resId; } GenericMaterialData OdTvVisualize2PrcGeomCollector::getGenericMaterialData(const OdGiMaterialTraitsTaker& traitsTaker, bool bGenericColorMaterial) const { GenericMaterialData data; OdGiMaterialColor giColor; OdGiMaterialMap giMatMap; double glossFactor = 0.; if (!bGenericColorMaterial) { traitsTaker.ambient(giColor); data.m_nAmbientMethod = static_cast(giColor.method()); data.m_nAmbientColor = giColor.color().color(); traitsTaker.diffuse(giColor, giMatMap); data.m_nDiffuseMethod = static_cast(giColor.method()); data.m_nDiffuseColor = giColor.color().color(); } traitsTaker.emission(giColor, giMatMap); data.m_nEmisisonMethod = static_cast(giColor.method()); data.m_nEmisionColor = giColor.color().color(); traitsTaker.specular(giColor, giMatMap, glossFactor); data.m_nSpecularMethod = static_cast(giColor.method()); data.m_nSpecularColor = giColor.color().color(); data.m_dGlossFactor = glossFactor; return data; }