/////////////////////////////////////////////////////////////////////////////// // 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. /////////////////////////////////////////////////////////////////////////////// #include "OdaCommon.h" #include "DgGeoMapImage.h" #include "DgBingMaps.h" #include "DgBingMapsCache.h" #include "Ge/GeLineSeg2d.h" #include "OdStack.h" #include "DgGiContext.h" #include "DgDatabase.h" #include "DgHostAppServices.h" #include "DynamicLinker.h" #include "DgGsManager.h" #include "Gs/GsBaseVectorizeDevice.h" #include "Gs/Gs.h" #include "Gi/GiRasterWrappers.h" #include "RxObjectImpl.h" //---------------------------------------------------------------------------------------------------------------------------------- double OdDgGeoMapHelper::getUnitScale(const OdDgGeoDataInfo* pGeoDataInfo, const OdDgModel* pModel) { double dRet = 1.0; OdDgModel::UnitDescription masterUnits; if (pModel) pModel->getMasterUnit(masterUnits); OdDgModel::UnitDescription csUnits; if (pGeoDataInfo && !pGeoDataInfo->getCoordinateSystem().isNull()) csUnits = OdDgGeoDataCoordinateSystem::getUnitDescription(pGeoDataInfo->getCoordinateSystem()->getUnits()); dRet = csUnits.m_denominator / csUnits.m_numerator / masterUnits.m_denominator * masterUnits.m_numerator; return dRet; } //---------------------------------------------------------------------------------------------------------------------------------- int OdDgGeoMapHelper::getOptimalLOD(const OdGeExtents3d& extXYZ, const OdDgGeoDataCoordinateConverter* pCoordConvertor, const OdDgGeoDataInfo* pGeoDataInfo, OdDgGeoMapImagePE::OdDgGeoMapImageResolution uResolution, double dImageWidth, double dImageHeight) { double dDiagonalLength = extXYZ.diagonal().length(); double dTilePixelDiaonalLength = sqrt(2 * 256 * 256); double dImagePixelDiaonalLength = sqrt(dImageWidth*dImageWidth + dImageHeight*dImageHeight); double dDevisor = 8; if (uResolution == OdDgGeoMapImagePE::kOptimal) dDevisor = 4; else if (uResolution == OdDgGeoMapImagePE::kFine) dDevisor = 2; else if (uResolution == OdDgGeoMapImagePE::kFiner) dDevisor = 1; OdUInt32 nOptimalTiles = (OdUInt32)ceil(dImagePixelDiaonalLength / dTilePixelDiaonalLength / dDevisor); // Optimal LOD OdGePoint3d ptDesign = extXYZ.minPoint(); OdGePoint3d ptDesignLLA; OdGePoint3d ptOffset; OdGePoint3d ptDesignMod; OdGePoint3d ptDesignModLLA; OdGePoint3d ptOffsetLLA; pCoordConvertor->transformXYZPointLL(ptDesign, ptDesignLLA); int iLOD = OdDgBingMaps::MIN_LOD; OdInt32 iTileX, iTileY; for (OdInt8 i = OdDgBingMaps::MIN_LOD; i <= OdDgBingMaps::MAX_LOD; ++i) { OdDgBingMaps::LatLongToTileXY(ptDesignLLA.y, ptDesignLLA.x, i, iTileX, iTileY); OdDgBingMaps::TileXYToLatLong(iTileX, iTileY, i, ptDesignModLLA.y, ptDesignModLLA.x); OdDgBingMaps::TileXYToLatLong(iTileX + 1, iTileY + 1, i, ptOffsetLLA.y, ptOffsetLLA.x); ptOffsetLLA.z = ptDesignLLA.z; if (pCoordConvertor->transformLLPointXYZ(ptDesignModLLA, ptDesignMod) != eOk) continue; if (pCoordConvertor->transformLLPointXYZ(ptOffsetLLA, ptOffset) != eOk) continue; iLOD = i; OdUInt32 nTiles = (OdUInt32)ceil(dDiagonalLength / ptDesignMod.distanceTo(ptOffset)); if( nTiles >= nOptimalTiles ) break; } return iLOD; } //---------------------------------------------------------------------------------------------------------------------------------- OdResult getXYZPointFromTile(const OdDgGeoDataCoordinateConverter* pCoordConvertor, OdInt8 nLOD, double dAltitude, OdInt32 iTileX, OdInt32 iTileY, OdGePoint3d& ptRet) { double dLat = 0, dLong = 0; OdDgBingMaps::TileXYToLatLong(iTileX, iTileY, nLOD, dLat, dLong); OdGePoint3d ptLL(dLong, dLat, dAltitude); OdResult retVal = pCoordConvertor->transformLLPointXYZ(ptLL, ptRet); return retVal; } //---------------------------------------------------------------------------------------------------------------------------------- OdResult getXYZPointToTile(const OdDgGeoDataCoordinateConverter* pCoordConvertor, OdInt8 nLOD, const OdGePoint3d& ptXYZ, OdInt32& iTileX, OdInt32& iTileY) { OdGePoint3d ptLL; OdResult retVal = pCoordConvertor->transformXYZPointLL(ptXYZ, ptLL); if( retVal != eOk ) return retVal; OdDgBingMaps::LatLongToTileXY(ptLL.y, ptLL.x, nLOD, iTileX, iTileY); return retVal; } //---------------------------------------------------------------------------------------------------------------------------------- OdUInt64 getTileKey(OdInt32 iTileX, OdInt32 iTileY) { OdUInt64 uTileIndex = (OdUInt32)iTileX; uTileIndex = uTileIndex << 32; uTileIndex += (OdUInt32)iTileY; return uTileIndex; } //---------------------------------------------------------------------------------------------------------------------------------- bool isTileProcessed(const std::set& setProcessedTiles, OdUInt64 uTileKey) { std::set::iterator pIter = setProcessedTiles.find(uTileKey); return pIter != setProcessedTiles.end(); } //---------------------------------------------------------------------------------------------------------------------------------- OdResult getTilePoint(OdUInt64 uTileKey, const OdDgGeoDataCoordinateConverter* pCoordConvertor, OdInt8 nLOD, double dAltitude, std::map& mapTilePoints, OdGePoint3d& ptResult) { std::map::iterator pIter = mapTilePoints.find(uTileKey); if(pIter != mapTilePoints.end()) { ptResult = pIter->second; return eOk; } OdInt32 iTileY = (OdInt32)(uTileKey & 0xFFFFFFFF); OdInt32 iTileX = (OdInt32)((uTileKey >> 32) & 0xFFFFFFFF); OdResult retVal = getXYZPointFromTile(pCoordConvertor, nLOD, dAltitude, iTileX, iTileY, ptResult); if (retVal != eOk) return retVal; mapTilePoints[uTileKey] = ptResult; return eOk; } //---------------------------------------------------------------------------------------------------------------------------------- bool hasSegmentIntersect(const OdGeExtents2d& ext2d, const OdGePoint2d& ptStart, const OdGePoint2d& ptEnd) { double dSegMaxX, dSegMinX, dSegMaxY, dSegMinY; double dExtMaxX = ext2d.maxPoint().x; double dExtMinX = ext2d.minPoint().x; double dExtMaxY = ext2d.maxPoint().y; double dExtMinY = ext2d.minPoint().y; if( ptStart.x > ptEnd.x ) { dSegMaxX = ptStart.x; dSegMinX = ptEnd.x; } else { dSegMinX = ptStart.x; dSegMaxX = ptEnd.x; } if (ptStart.y > ptEnd.y) { dSegMaxY = ptStart.y; dSegMinY = ptEnd.y; } else { dSegMinY = ptStart.y; dSegMaxY = ptEnd.y; } if( (dSegMaxX < dExtMinX) || (dSegMinX > dExtMaxX) || (dSegMaxY < dExtMinY) || (dSegMinY > dExtMaxY) ) return false; if( OdEqual(dSegMaxX, dSegMinX) ) { if (((dSegMaxY > dExtMaxY) && (dSegMinY < dExtMaxY)) || ((dSegMaxY > dExtMinY) && (dSegMinY < dExtMinY))) return true; else return false; } else if( OdEqual(dSegMaxY, dSegMinY) ) { if (((dSegMaxX > dExtMaxX) && (dSegMinX < dExtMaxX)) || ((dSegMaxX > dExtMinX) && (dSegMinX < dExtMinX))) return true; else return false; } else { double dK = (ptEnd.y - ptStart.y) / (ptEnd.x - ptStart.x); double dB = ptStart.y - dK * ptStart.x; double dExtMinYIsect = dK * dExtMinX + dB; if ((dExtMinYIsect >= dExtMinY) && (dExtMinYIsect <= dExtMaxY)) return true; double dExtMaxYIsect = dK * dExtMaxX + dB; if ((dExtMaxYIsect >= dExtMinY) && (dExtMaxYIsect <= dExtMaxY)) return true; double dExtMinXIsect = (dExtMinY - dB) / dK; if ((dExtMinXIsect >= dExtMinX) && (dExtMinXIsect <= dExtMaxX)) return true; double dExtMaxXIsect = (dExtMaxY - dB) / dK; if ((dExtMaxXIsect >= dExtMinX) && (dExtMaxXIsect <= dExtMaxX)) return true; } return false; } //---------------------------------------------------------------------------------------------------------------------------------- bool hasPolygonIntersects(const OdGeExtents3d& extXYZ, const OdGePoint3d& ptBottomLeft, const OdGePoint3d& ptTopLeft, const OdGePoint3d& ptTopRight, const OdGePoint3d& ptBottomRight) { OdGeExtents2d ext2d; extXYZ.convert2d(ext2d); if (hasSegmentIntersect(ext2d, ptBottomLeft.convert2d(), ptTopLeft.convert2d())) return true; if (hasSegmentIntersect(ext2d, ptTopLeft.convert2d(), ptTopRight.convert2d())) return true; if (hasSegmentIntersect(ext2d, ptTopRight.convert2d(), ptBottomRight.convert2d())) return true; if (hasSegmentIntersect(ext2d, ptBottomRight.convert2d(), ptBottomLeft.convert2d())) return true; return false; } //---------------------------------------------------------------------------------------------------------------------------------- OdResult addDgTiles(const OdGeExtents3d& extXYZ, OdDgGeoMapImagePE::OdDgGeoMapImageType eGeoMapType, OdInt8 nLOD, const OdDgGeoDataCoordinateConverter* pCoordConvertor, OdArray& arrTilesToProcess, std::map& mapTilePoints, std::set& setProcessedTiles, std::set& arrTiles) { OdArray arrProcessingTiles = arrTilesToProcess; arrTilesToProcess.clear(); for (OdUInt32 i = 0; i < arrProcessingTiles.size(); i++) { OdUInt64 uBottomLeftKey = arrProcessingTiles[i]; if (isTileProcessed(setProcessedTiles, uBottomLeftKey)) continue; OdInt32 iBaseTileY = (OdInt32)(uBottomLeftKey & 0xFFFFFFFF); OdInt32 iBaseTileX = (OdInt32)((uBottomLeftKey >> 32) & 0xFFFFFFFF); setProcessedTiles.insert(uBottomLeftKey); OdUInt64 uBottomRightKey = getTileKey(iBaseTileX + 1, iBaseTileY); OdUInt64 uTopLeftKey = getTileKey(iBaseTileX, iBaseTileY + 1); OdUInt64 uTopRightKey = getTileKey(iBaseTileX + 1, iBaseTileY + 1); OdGePoint3d ptBottomLeft; OdGePoint3d ptTopLeft; OdGePoint3d ptBottomRight; OdGePoint3d ptTopRight; OdResult retVal = getTilePoint(uBottomLeftKey, pCoordConvertor, nLOD, 0.0, mapTilePoints, ptBottomLeft); if (retVal != eOk) return retVal; retVal = getTilePoint(uBottomRightKey, pCoordConvertor, nLOD, 0.0, mapTilePoints, ptBottomRight); if (retVal != eOk) return retVal; retVal = getTilePoint(uTopLeftKey, pCoordConvertor, nLOD, 0.0, mapTilePoints, ptTopLeft); if (retVal != eOk) return retVal; retVal = getTilePoint(uTopRightKey, pCoordConvertor, nLOD, 0.0, mapTilePoints, ptTopRight); if (retVal != eOk) return retVal; char cMapTypeId = (eGeoMapType == OdDgGeoMapImagePE::kAerial) ? 'a' : (eGeoMapType == OdDgGeoMapImagePE::kHybrid) ? 'h' : 'r'; double dMinX = ptBottomLeft.x; double dMaxX = ptBottomLeft.x; double dMinY = ptBottomLeft.y; double dMaxY = ptBottomLeft.y; OdGePoint3d boxPts[3]; boxPts[0] = ptTopLeft; boxPts[1] = ptTopRight; boxPts[2] = ptBottomRight; for (OdUInt32 i = 0; i < 3; i++) { if (boxPts[i].x > dMaxX) dMaxX = boxPts[i].x; if (boxPts[i].x < dMinX) dMinX = boxPts[i].x; if (boxPts[i].y > dMaxY) dMaxY = boxPts[i].y; if (boxPts[i].y < dMinY) dMinY = boxPts[i].y; } bool bHasIntersect = hasPolygonIntersects(extXYZ, ptBottomLeft, ptTopLeft, ptTopRight, ptBottomRight); bool bOneTile = false; bool bInternalTile = false; if( !bHasIntersect ) { bInternalTile = ((dMaxX < extXYZ.maxPoint().x) && (dMinX > extXYZ.minPoint().x) && (dMaxY < extXYZ.maxPoint().y) && (dMinY > extXYZ.minPoint().y)); if( !bInternalTile ) bOneTile = ((dMaxX >= extXYZ.maxPoint().x) && (dMinX <= extXYZ.minPoint().x) && (dMaxY >= extXYZ.maxPoint().y) && (dMinY <= extXYZ.minPoint().y)); } if( bHasIntersect || bInternalTile || bOneTile ) { OdDgGeoMapTile newTile(cMapTypeId, nLOD, iBaseTileX, iBaseTileY); newTile.setPoints(ptBottomLeft, ptTopLeft, ptTopRight, ptBottomRight); arrTiles.insert(newTile); arrTilesToProcess.push_back(getTileKey(iBaseTileX + 1, iBaseTileY)); arrTilesToProcess.push_back(getTileKey(iBaseTileX - 1, iBaseTileY)); arrTilesToProcess.push_back(getTileKey(iBaseTileX, iBaseTileY + 1)); arrTilesToProcess.push_back(getTileKey(iBaseTileX, iBaseTileY - 1)); } } return eOk; } //---------------------------------------------------------------------------------------------------------------------------------- OdResult OdDgGeoMapHelper::getDgGeoMapTiles(const OdGeExtents3d& extXYZ, const OdGeVector3d& vrOriginOffset, OdDgGeoMapImagePE::OdDgGeoMapImageType eGeoMapType, OdInt8 nLOD, const OdDgGeoDataCoordinateConverter* pCoordConvertor, std::set& arrTiles) { std::map mapTilePoints; std::set setProcessedTiles; OdGeExtents3d extDrawing = extXYZ; extDrawing.transformBy(OdGeMatrix3d::translation(vrOriginOffset)); OdGePoint3d ptMinXYZ = extDrawing.minPoint(); OdInt32 iMinPixelX = 0, iMinPixelY = 0; OdResult retVal = getXYZPointToTile(pCoordConvertor, nLOD, ptMinXYZ, iMinPixelX, iMinPixelY); if (retVal != eOk) return retVal; OdArray arrTilesToProcess; OdUInt64 uMinPtKey = getTileKey(iMinPixelX, iMinPixelY); arrTilesToProcess.push_back(uMinPtKey); while( !arrTilesToProcess.isEmpty() ) { retVal = addDgTiles(extDrawing, eGeoMapType, nLOD, pCoordConvertor, arrTilesToProcess, mapTilePoints, setProcessedTiles, arrTiles); if (retVal != eOk) return retVal; } return retVal; } //---------------------------------------------------------------------------------------------------------------------------------- OdResult OdDgGeoMapHelper::getMap(const OdDgGeoDataInfo* pGeoDataInfo, const OdDgModel* pBaseModel, const OdDgGeoDataCoordinateConverter* pCoordConvertor, OdDgGeoMapImagePE::OdDgGeoMapImageType eGeoMapType, int iLOD, OdDgGeoMapImagePE::OdDgGeoMapImageResolution uResolution, const OdGeExtents3d& extRect, const OdGeVector3d& vrOriginOffset, double dImageWidth, double dImageHeight, OdGiRasterImagePtr& pImg) { OdDgDatabase* pHostDb = pGeoDataInfo->database(); if( !pHostDb ) return eWrongDatabase; OdDgHostAppServices* pAppServices = pHostDb->appServices(); OdDgDatabasePtr pDb = pAppServices->createDatabase(); if (pDb.isNull()) return eCreateFailed; OdGsDevicePtr pDevice; OdGsModulePtr pGs = ::odrxDynamicLinker()->loadModule(OdWinBitmapModuleName); if (!pGs.isNull()) pDevice = pGs->createBitmapDevice(); if (pDevice.isNull()) return eDeviceNotFound; OdGiContextForDgDatabasePtr pDgnContext = OdGiContextForDgDatabase::createObject(); pDgnContext->setDatabase(pDb); pDgnContext->enableGsModel(false); OdDgViewGroupTablePtr pVGTable = pDb->getViewGroupTable(OdDg::kForRead); OdDgViewGroupPtr pVG; OdDgViewPtr pView; if (!pVGTable.isNull()) pVG = pVGTable->createIterator()->item().openObject(OdDg::kForRead); if (!pVG.isNull()) pView = pVG->createIterator()->item().openObject(OdDg::kForRead); OdDgElementId idView; if (!pView.isNull()) idView = pView->elementId(); else return eNullEntityPointer; pDevice = OdGsDeviceForDgModel::setupModelView(pDb->getActiveModelId(), idView, pDevice, pDgnContext); const ODCOLORREF* refColors = OdDgColorTable::currentPalette(pDb); ODGSPALETTE pPalCpy; pPalCpy.insert(pPalCpy.begin(), refColors, refColors + 256); //pPalCpy[254] = refColors[0]; OdDgModelPtr pModel = pDb->getActiveModelId().safeOpenObject(); ODCOLORREF background = pModel->getBackground(); pPalCpy[255] = background; bool bCorrected = OdDgColorTable::correctPaletteForWhiteBackground(pPalCpy.asArrayPtr()); pDgnContext->setPaletteBackground(background); pDevice->setBackgroundColor(background); pDevice->setLogicalPalette(pPalCpy.asArrayPtr(), 256); OdGsDCRect screenRect(OdGsDCPoint(0, (long)dImageHeight), OdGsDCPoint((long)dImageWidth, 0)); pDevice->onSize(screenRect); OdGsView* pGsView = pDevice->viewAt(0); double dWidth = extRect.maxPoint().x - extRect.minPoint().x; double dHeight = extRect.maxPoint().y - extRect.minPoint().y; OdGePoint3d ptCenter = extRect.center(); pGsView->setView( ptCenter + OdGeVector3d::kZAxis, ptCenter, OdGeVector3d::kYAxis, dWidth, dHeight); pGsView->setMode(OdGsView::k2DOptimized); OdDgGeoMapImageCreatorPtr pGeoMapImageCreator = OdDgGeoMapImageCreator::createObject(); pGeoMapImageCreator->init(pGeoDataInfo, pBaseModel, pCoordConvertor, eGeoMapType, iLOD, uResolution, extRect, vrOriginOffset, dImageWidth, dImageHeight); pGsView->add(pGeoMapImageCreator, NULL); pDevice->update(); OdGiRasterImagePtr pImage = OdGiRasterImage::cast(pDevice->properties()->getAt(OD_T("RasterImage"))); OdSmartPtr pDesc = OdGiRasterImageDesc::createObject(pImage); pDesc->setColorDepth(32); pDesc->pixelFormat().setRGBA(); pDesc->setScanLinesAlignment(4); OdGiRasterImagePtr pRaster = pImage->convert(true, 50., 50., 0.0, 0, false, false, false, pDesc, true); pImg = pRaster; return eOk; } //////////////////////// //OdDgGeoMapImageCreator OdDgGeoMapImageCreator::OdDgGeoMapImageCreator() : m_pGsNode(0) , m_nRefCounter(1) { } void OdDgGeoMapImageCreator::addRef() { ++m_nRefCounter; } void OdDgGeoMapImageCreator::release() ODRX_NOEXCEPT { ODA_ASSERT((m_nRefCounter > 0)); if (!(--m_nRefCounter)) { delete this; } } long OdDgGeoMapImageCreator::numRefs() const { return m_nRefCounter; } void OdDgGeoMapImageCreator::setGsNode(OdGsCache* pGsNode) { m_pGsNode = pGsNode; } OdGsCache* OdDgGeoMapImageCreator::gsNode() const { return m_pGsNode; } bool OdDgGeoMapImageCreator::isPersistent() const { return false; } OdDbStub* OdDgGeoMapImageCreator::id() const { return 0; } OdDgGeoMapImageCreator::~OdDgGeoMapImageCreator() { if (m_pGsNode) { m_pGsNode->setDrawableNull(); } } void OdDgGeoMapImageCreator::init(const OdDgGeoDataInfo* pGeoDataInfo, const OdDgModel* pModel, const OdDgGeoDataCoordinateConverter* pCoordConvertor, OdDgGeoMapImagePE::OdDgGeoMapImageType eGeoMapType, int iLOD, OdDgGeoMapImagePE::OdDgGeoMapImageResolution uResolution, const OdGeExtents3d& extXYZ, const OdGeVector3d& vrOriginOffset, double dImageWidth, double dImageHeight ) { m_pGeoDataInfo = pGeoDataInfo; m_pModel = pModel; m_pCoordConvertor = pCoordConvertor; m_eGeoMapType = eGeoMapType; m_iLOD = iLOD; m_uResolution = uResolution; m_extXYZ = extXYZ; m_vrOriginOffset = vrOriginOffset; m_dImageWidth = dImageWidth; m_dImageHeight = dImageHeight; } OdDgGeoMapImageCreatorPtr OdDgGeoMapImageCreator::createObject() { return OdRxObjectImpl::createObject(); } OdUInt32 OdDgGeoMapImageCreator::subSetAttributes(OdGiDrawableTraits* pTraits) const { return kDrawableRegenDraw; } bool OdDgGeoMapImageCreator::subWorldDraw(OdGiWorldDraw* pWd) const { return false; } void OdDgGeoMapImageCreator::subViewportDraw(OdGiViewportDraw* pVd) const { drawGeoMap(pVd, m_pGeoDataInfo, m_pModel, m_pCoordConvertor, m_eGeoMapType, m_iLOD, m_uResolution, m_extXYZ, m_vrOriginOffset); //TODO: status } void drawDgTiles( OdGiViewportDraw* pVd, const OdDgGeoDataInfo* pGeoDataInfo, const OdDgModel* pModel, const OdDgGeoDataCoordinateConverter* pCoordConvertor, const OdGePoint2dArray & arrGlobalMapExtents, const std::set & arrTiles, const OdArray & arrTilesImages, const OdGeVector3d& vrOriginOffset) { // clipping boundary OdGiClipBoundary boundary; boundary.m_vNormal = OdGeVector3d::kZAxis; boundary.m_Points = arrGlobalMapExtents; boundary.m_dFrontClipZ = 0.; boundary.m_dBackClipZ = 0.; boundary.m_bClippingFront = false; boundary.m_bClippingBack = false; boundary.m_bDrawBoundary = false; pVd->geometry().pushClipBoundary(&boundary); double dZCorrection = 0.1; double dHorizontalUnitScale = OdDgGeoMapHelper::getUnitScale(pGeoDataInfo, pModel); if (dHorizontalUnitScale > OdGeContext::gTol.equalPoint()) { dZCorrection = 0.1 / dHorizontalUnitScale; } if (pVd->viewport().viewDir().z > 0) { dZCorrection = -dZCorrection; } OdUInt32 uIndex = 0; std::set::const_iterator pIt = arrTiles.begin(); std::set::const_iterator pEnd = arrTiles.end(); for (; pIt != pEnd; ++pIt, ++uIndex) { // get chunk clip boundary const OdDgGeoMapTile& tile = *pIt; OdGePoint3dArray arrChunkVertices; arrChunkVertices.resize(4); tile.getPoints(arrChunkVertices[0], arrChunkVertices[1], arrChunkVertices[2], arrChunkVertices[3]); for (OdUInt32 i = 0; i < 4; ++i) { arrChunkVertices[i] -= vrOriginOffset; arrChunkVertices[i].z = dZCorrection; } // draw tile odgiImageViewport(pVd->geometry(), arrTilesImages[uIndex], arrChunkVertices.asArrayPtr()); } pVd->geometry().popClipBoundary(); } OdResult OdDgGeoMapImageCreator::drawGeoMap(OdGiViewportDraw* pVd, const OdDgGeoDataInfo* pGeoDataInfo, const OdDgModel* pModel, const OdDgGeoDataCoordinateConverter* pCoordConvertor, OdDgGeoMapImagePE::OdDgGeoMapImageType eGeoMapType, int iLOD, OdDgGeoMapImagePE::OdDgGeoMapImageResolution uResolution, const OdGeExtents3d& extXYZ, const OdGeVector3d& vrOriginOffset ) const { OdGiDrawFlagsHelper autoFlags(pVd->subEntityTraits(), OdGiSubEntityTraits::kExcludeFromViewExt); OdDgGeoDataCoordinateSystemPtr pCoordSystem; if (pGeoDataInfo) pCoordSystem = pGeoDataInfo->getCoordinateSystem(); if (pCoordSystem.isNull()) return eNullPtr; // get map extents OdGePoint2dArray arrMapExtents; arrMapExtents.push_back(extXYZ.minPoint().convert2d()); arrMapExtents.push_back(OdGePoint2d(extXYZ.minPoint().x, extXYZ.maxPoint().y)); arrMapExtents.push_back(extXYZ.maxPoint().convert2d()); arrMapExtents.push_back(OdGePoint2d(extXYZ.maxPoint().x, extXYZ.minPoint().y)); // get all needed tiles // get all needed tiles std::set arrTiles; OdResult res = OdDgGeoMapHelper::getDgGeoMapTiles(extXYZ, vrOriginOffset, eGeoMapType, iLOD, pCoordConvertor, arrTiles); if (eOk != res) return res; // get all tiles images OdArray arrTilesImages; res = g_OdDgBingMapsCache->getTiles(arrTiles, arrTilesImages); if (eOk != res) { return res; } //draw tiles drawDgTiles(pVd, pGeoDataInfo, pModel, pCoordConvertor, arrMapExtents, arrTiles, arrTilesImages, vrOriginOffset); { // drawing bing logo "powered by" OdGiRasterImagePtr pRasterLogo; if (eOk == g_OdDgBingMapsCache->getBrandLogo(pRasterLogo)) { double dPixelSize = (arrMapExtents[2].x - arrMapExtents[0].x) / m_dImageWidth; double dResultScale = dPixelSize * 0.2 * m_dImageWidth / pRasterLogo->pixelWidth(); OdGeVector3d vU = OdGeVector3d::kXAxis * dResultScale; OdGeVector3d vV = OdGeVector3d::kYAxis * dResultScale; OdGePoint3d ptOrigin(OdGePoint3d(extXYZ.maxPoint().x, extXYZ.minPoint().y, extXYZ.minPoint().z) - vU * pRasterLogo->pixelWidth()); OdGePoint2dArray arrLogoClipBoundary; arrLogoClipBoundary.resize(5); arrLogoClipBoundary[0].set(0., 0.); arrLogoClipBoundary[1].set(pRasterLogo->pixelWidth(), 0.); arrLogoClipBoundary[2].set(pRasterLogo->pixelWidth(), pRasterLogo->pixelHeight()); arrLogoClipBoundary[3].set(0., pRasterLogo->pixelHeight()); arrLogoClipBoundary[4] = arrLogoClipBoundary[0]; pVd->geometry().rasterImageDc(ptOrigin, vU, vV, pRasterLogo, arrLogoClipBoundary.asArrayPtr(), arrLogoClipBoundary.size(), true); } } return eOk; } //----------------------------------------------------------------------------------------------------------------------------------