From 8cf50ece74da2887b1ba734f66547f4ae6444763 Mon Sep 17 00:00:00 2001 From: tteuling Date: Thu, 14 Oct 2021 16:34:12 +0200 Subject: [PATCH] Drop PolyData Split PrepareArea Add Projection::BoundingBoxToPixel --- .../src/osmscout/MapPainterAgg.cpp | 6 +- .../src/osmscout/MapPainterCairo.cpp | 6 +- .../src/osmscout/MapPainterDirectX.cpp | 11 +- .../src/osmscout/MapPainterGDI.cpp | 7 +- .../src/osmscout/MapPainterIOS.mm | 6 +- .../src/osmscout/MapPainterQt.cpp | 6 +- .../src/osmscout/MapPainterSVG.cpp | 10 +- .../include/osmscoutmap/MapPainter.h | 33 +- .../src/osmscoutmap/MapPainter.cpp | 353 ++++++++---------- .../include/osmscout/util/Projection.h | 10 + libosmscout/src/osmscout/util/Projection.cpp | 72 ++++ 11 files changed, 277 insertions(+), 243 deletions(-) diff --git a/libosmscout-map-agg/src/osmscout/MapPainterAgg.cpp b/libosmscout-map-agg/src/osmscout/MapPainterAgg.cpp index 148e3122b..8cc62c556 100644 --- a/libosmscout-map-agg/src/osmscout/MapPainterAgg.cpp +++ b/libosmscout-map-agg/src/osmscout/MapPainterAgg.cpp @@ -665,9 +665,9 @@ namespace osmscout { for (const auto& data : area.clippings) { agg::path_storage clipPath; - clipPath.move_to(coordBuffer.buffer[data.transStart].GetX(), - coordBuffer.buffer[data.transStart].GetY()); - for (size_t i=data.transStart+1; i<=data.transEnd; i++) { + clipPath.move_to(coordBuffer.buffer[data.GetStart()].GetX(), + coordBuffer.buffer[data.GetStart()].GetY()); + for (size_t i=data.GetStart()+1; i<=data.GetEnd(); i++) { clipPath.line_to(coordBuffer.buffer[i].GetX(), coordBuffer.buffer[i].GetY()); } diff --git a/libosmscout-map-cairo/src/osmscout/MapPainterCairo.cpp b/libosmscout-map-cairo/src/osmscout/MapPainterCairo.cpp index 2c1580644..560648620 100644 --- a/libosmscout-map-cairo/src/osmscout/MapPainterCairo.cpp +++ b/libosmscout-map-cairo/src/osmscout/MapPainterCairo.cpp @@ -1347,9 +1347,9 @@ namespace osmscout { cairo_new_sub_path(draw); cairo_set_line_width(draw,0.0); cairo_move_to(draw, - coordBuffer.buffer[data.transStart].GetX(), - coordBuffer.buffer[data.transStart].GetY()); - for (size_t i=data.transStart+1; i<=data.transEnd; i++) { + coordBuffer.buffer[data.GetStart()].GetX(), + coordBuffer.buffer[data.GetStart()].GetY()); + for (size_t i=data.GetStart()+1; i<=data.GetEnd(); i++) { cairo_line_to(draw, coordBuffer.buffer[i].GetX(), coordBuffer.buffer[i].GetY()); diff --git a/libosmscout-map-directx/src/osmscout/MapPainterDirectX.cpp b/libosmscout-map-directx/src/osmscout/MapPainterDirectX.cpp index fd6c6c246..ab1e2c60f 100644 --- a/libosmscout-map-directx/src/osmscout/MapPainterDirectX.cpp +++ b/libosmscout-map-directx/src/osmscout/MapPainterDirectX.cpp @@ -976,10 +976,7 @@ namespace osmscout m_pRenderTarget->DrawGeometry(pPathGeometry, GetColorBrush(borderStyle->GetColor()), borderWidth, GetStrokeStyle(borderStyle->GetDash())); pPathGeometry->Release(); - for (std::list::const_iterator c = area.clippings.begin(); - c != area.clippings.end(); - c++) { - const PolyData &data = *c; + for (const auto& data : area.clippings) { ID2D1PathGeometry* pPathGeometry; HRESULT hr = m_pDirect2dFactory->CreatePathGeometry(&pPathGeometry); if (SUCCEEDED(hr)) @@ -988,9 +985,11 @@ namespace osmscout hr = pPathGeometry->Open(&pSink); if (SUCCEEDED(hr)) { - pSink->BeginFigure(POINTF(coordBuffer.buffer[data.transStart].GetX(), coordBuffer.buffer[data.transStart].GetY()), D2D1_FIGURE_BEGIN_FILLED); + pSink->BeginFigure(POINTF(coordBuffer.buffer[data.GetStart()].GetX(), + coordBuffer.buffer[data.GetStart()].GetY()), + D2D1_FIGURE_BEGIN_FILLED); - for (size_t i = data.transStart + 1; i <= data.transEnd; i++) { + for (size_t i = data.GetStart() + 1; i <= data.GetEnd(); i++) { pSink->AddLine(POINTF(coordBuffer.buffer[i].GetX(), coordBuffer.buffer[i].GetY())); } pSink->EndFigure(D2D1_FIGURE_END_CLOSED); diff --git a/libosmscout-map-gdi/src/osmscout/MapPainterGDI.cpp b/libosmscout-map-gdi/src/osmscout/MapPainterGDI.cpp index 38731b972..de203f480 100644 --- a/libosmscout-map-gdi/src/osmscout/MapPainterGDI.cpp +++ b/libosmscout-map-gdi/src/osmscout/MapPainterGDI.cpp @@ -747,13 +747,10 @@ namespace osmscout { Gdiplus::Region* region; }; std::vector clippingInfo; - for (std::list::const_iterator c = area.clippings.begin(); - c != area.clippings.end(); - ++c) { - const PolyData &data = *c; + for (const auto& data : area.clippings) { clippingRegion cr; cr.points = new PointFBuffer(); - for (size_t i = data.transStart; i <= data.transEnd; i++) { + for (size_t i = data.GetStart(); i <= data.GetEnd(); i++) { cr.points->AddPoint(coordBuffer.buffer[i].GetX(), coordBuffer.buffer[i].GetY()); } cr.points->Close(); diff --git a/libosmscout-map-iosx/src/osmscout/MapPainterIOS.mm b/libosmscout-map-iosx/src/osmscout/MapPainterIOS.mm index 8476bffd5..f223faa23 100644 --- a/libosmscout-map-iosx/src/osmscout/MapPainterIOS.mm +++ b/libosmscout-map-iosx/src/osmscout/MapPainterIOS.mm @@ -914,9 +914,9 @@ static void DrawPattern (void * info,CGContextRef cg){ if (!area.clippings.empty()) { for (const auto& data : area.clippings) { - CGContextMoveToPoint(cg,coordBuffer.buffer[data.transStart].GetX(), - coordBuffer.buffer[data.transStart].GetY()); - for (size_t i=data.transStart+1; i<=data.transEnd; i++) { + CGContextMoveToPoint(cg,coordBuffer.buffer[data.GetStart()].GetX(), + coordBuffer.buffer[data.GetStart()].GetY()); + for (size_t i=data.GetStart()+1; i<=data.GetEnd(); i++) { CGContextAddLineToPoint(cg,coordBuffer.buffer[i].GetX(), coordBuffer.buffer[i].GetY()); } diff --git a/libosmscout-map-qt/src/osmscout/MapPainterQt.cpp b/libosmscout-map-qt/src/osmscout/MapPainterQt.cpp index ef86c2616..b6850fc3e 100644 --- a/libosmscout-map-qt/src/osmscout/MapPainterQt.cpp +++ b/libosmscout-map-qt/src/osmscout/MapPainterQt.cpp @@ -901,10 +901,10 @@ namespace osmscout { if (!area.clippings.empty()) { for (const auto& data : area.clippings) { - path.moveTo(coordBuffer.buffer[data.transStart].GetX(), - coordBuffer.buffer[data.transStart].GetY()); + path.moveTo(coordBuffer.buffer[data.GetStart()].GetX(), + coordBuffer.buffer[data.GetStart()].GetY()); - for (size_t i=data.transStart+1; i<=data.transEnd; i++) { + for (size_t i=data.GetStart()+1; i<=data.GetEnd(); i++) { path.lineTo(coordBuffer.buffer[i].GetX(), coordBuffer.buffer[i].GetY()); } diff --git a/libosmscout-map-svg/src/osmscout/MapPainterSVG.cpp b/libosmscout-map-svg/src/osmscout/MapPainterSVG.cpp index 2e476deb8..dd9fbf2d9 100644 --- a/libosmscout-map-svg/src/osmscout/MapPainterSVG.cpp +++ b/libosmscout-map-svg/src/osmscout/MapPainterSVG.cpp @@ -1013,13 +1013,9 @@ namespace osmscout { } stream << " Z"; - for (std::list::const_iterator c=area.clippings.begin(); - c!=area.clippings.end(); - ++c) { - const PolyData &data=*c; - - stream << "M " << coordBuffer.buffer[data.transStart].GetX() << " " << coordBuffer.buffer[data.transStart].GetY(); - for (size_t i=data.transStart+1; i<=data.transEnd; i++) { + for (const auto& data : area.clippings) { + stream << "M " << coordBuffer.buffer[data.GetStart()].GetX() << " " << coordBuffer.buffer[data.GetStart()].GetY(); + for (size_t i=data.GetStart()+1; i<=data.GetEnd(); i++) { stream << " L " << coordBuffer.buffer[i].GetX() << " " << coordBuffer.buffer[i].GetY(); } stream << " Z"; diff --git a/libosmscout-map/include/osmscoutmap/MapPainter.h b/libosmscout-map/include/osmscoutmap/MapPainter.h index be2e31d9c..e4ecd1a26 100644 --- a/libosmscout-map/include/osmscoutmap/MapPainter.h +++ b/libosmscout-map/include/osmscoutmap/MapPainter.h @@ -167,26 +167,20 @@ namespace osmscout { double mainSlotWidth; //!< Width of main slot, used for relative positioning }; - struct OSMSCOUT_MAP_API PolyData - { - size_t transStart; //!< Start of coordinates in transformation buffer - size_t transEnd; //!< End of coordinates in transformation buffer (inclusive) - }; - /** * Data structure for holding temporary data about areas */ struct OSMSCOUT_MAP_API AreaData { - ObjectFileRef ref; - TypeInfoRef type; - const FeatureValueBuffer *buffer; //!< Features of the line segment, can be NULL in case of border only areas - FillStyleRef fillStyle; //!< Fill style - BorderStyleRef borderStyle; //!< Border style - GeoBox boundingBox; //!< Bounding box of the area - bool isOuter; //!< flag if this area is outer ring of some relation - CoordBufferRange coordRange; //!< Range of coordinates in transformation buffer - std::list clippings; //!< Clipping polygons to be used during drawing of this area + ObjectFileRef ref; + TypeInfoRef type; + const FeatureValueBuffer *buffer; //!< Features of the line segment, can be NULL in case of border only areas + FillStyleRef fillStyle; //!< Fill style + BorderStyleRef borderStyle; //!< Border style + GeoBox boundingBox; //!< Bounding box of the area + bool isOuter; //!< flag if this area is outer ring of some relation + CoordBufferRange coordRange; //!< Range of coordinates in transformation buffer + std::list clippings; //!< Clipping polygons to be used during drawing of this area }; using WayPathDataIt=std::list::iterator; @@ -316,6 +310,15 @@ namespace osmscout { const MapParameter& parameter, const MapData& data); + bool PrepareAreaRing(const StyleConfig& styleConfig, + const Projection& projection, + const MapParameter& parameter, + const std::vector& coordRanges, + const Area& area, + const Area::Ring& ring, + size_t i, + const TypeInfoRef& type); + void PrepareArea(const StyleConfig& styleConfig, const Projection& projection, const MapParameter& parameter, diff --git a/libosmscout-map/src/osmscoutmap/MapPainter.cpp b/libosmscout-map/src/osmscoutmap/MapPainter.cpp index dc1ef90a4..2a98fdee2 100644 --- a/libosmscout-map/src/osmscoutmap/MapPainter.cpp +++ b/libosmscout-map/src/osmscoutmap/MapPainter.cpp @@ -425,46 +425,16 @@ namespace osmscout { return false; } - double x; - double y; - - projection.GeoToPixel(boundingBox.GetMinCoord(), - x, - y); - - double xMin=x; - double xMax=x; - double yMin=y; - double yMax=y; - - projection.GeoToPixel(boundingBox.GetMaxCoord(), - x, - y); - - xMin=std::min(xMin,x); - xMax=std::max(xMax,x); - yMin=std::min(yMin,y); - yMax=std::max(yMax,y); - - projection.GeoToPixel(GeoCoord(boundingBox.GetMinLat(), - boundingBox.GetMaxLon()), - x, - y); - - xMin=std::min(xMin,x); - xMax=std::max(xMax,x); - yMin=std::min(yMin,y); - yMax=std::max(yMax,y); - - projection.GeoToPixel(GeoCoord(boundingBox.GetMaxLat(), - boundingBox.GetMinLon()), - x, - y); - - xMin=std::min(xMin,x); - xMax=std::max(xMax,x); - yMin=std::min(yMin,y); - yMax=std::max(yMax,y); + double xMin; + double xMax; + double yMin; + double yMax; + + if (!projection.BoundingBoxToPixel(boundingBox, + xMin,yMin, + xMax,yMax)) { + return false; + } xMin=xMin-pixelOffset; xMax=xMax+pixelOffset; @@ -486,51 +456,17 @@ namespace osmscout { const GeoBox& boundingBox, double pixelOffset) const { - if (!boundingBox.IsValid()){ + double xMin; + double xMax; + double yMin; + double yMax; + + if (!projection.BoundingBoxToPixel(boundingBox, + xMin,yMin, + xMax,yMax)) { return false; } - double x; - double y; - - projection.GeoToPixel(boundingBox.GetMinCoord(), - x, - y); - - double xMin=x; - double xMax=x; - double yMin=y; - double yMax=y; - - projection.GeoToPixel(boundingBox.GetMaxCoord(), - x, - y); - - xMin=std::min(xMin,x); - xMax=std::max(xMax,x); - yMin=std::min(yMin,y); - yMax=std::max(yMax,y); - - projection.GeoToPixel(GeoCoord(boundingBox.GetMinLat(), - boundingBox.GetMaxLon()), - x, - y); - - xMin=std::min(xMin,x); - xMax=std::max(xMax,x); - yMin=std::min(yMin,y); - yMax=std::max(yMax,y); - - projection.GeoToPixel(GeoCoord(boundingBox.GetMaxLat(), - boundingBox.GetMinLon()), - x, - y); - - xMin=std::min(xMin,x); - xMax=std::max(xMax,x); - yMin=std::min(yMin,y); - yMax=std::max(yMax,y); - xMin=xMin-pixelOffset; xMax=xMax+pixelOffset; yMin=yMin-pixelOffset; @@ -560,7 +496,7 @@ namespace osmscout { const MapParameter& /*parameter*/, const MapData& /*data*/) { - // No code + // Nothing to do in the base class implementation } void MapPainter::BeforeDrawing(const StyleConfig& /*styleConfig*/, @@ -1296,6 +1232,131 @@ namespace osmscout { } } + bool MapPainter::PrepareAreaRing(const StyleConfig& styleConfig, + const Projection& projection, + const MapParameter& parameter, + const std::vector& coordRanges, + const Area& area, + const Area::Ring& ring, + size_t i, + const TypeInfoRef& type) + { + if (type->GetIgnore()) { + // clipping inner ring, we will not render it, but still go deeper, + // there may be nested outer rings + return true; + } + + if (!coordRanges[i].IsValid()) { + return false; // ring was skipped or reduced to single point + } + + FillStyleRef fillStyle; + std::vector borderStyles; + BorderStyleRef borderStyle; + + fillStyle=styleConfig.GetAreaFillStyle(type, + ring.GetFeatureValueBuffer(), + projection); + + FillStyleProcessorRef fillProcessor=parameter.GetFillStyleProcessor(ring.GetType()->GetIndex()); + + if (fillProcessor) { + fillStyle=fillProcessor->Process(ring.GetFeatureValueBuffer(), + fillStyle); + } + + styleConfig.GetAreaBorderStyles(type, + ring.GetFeatureValueBuffer(), + projection, + borderStyles); + + if (!fillStyle && borderStyles.empty()) { + // Nothing to draw + return false; + } + + size_t borderStyleIndex=0; + + // Get the borderStyle of the border itself + if (!borderStyles.empty() && + borderStyles.front()->GetDisplayOffset()==0.0 && + borderStyles.front()->GetOffset()==0.0) { + borderStyle=borderStyles[borderStyleIndex]; + borderStyleIndex++; + } + + AreaData a; + double borderWidth=borderStyle ? borderStyle->GetWidth() : 0.0; + + a.boundingBox=ring.GetBoundingBox(); + a.isOuter = ring.IsOuter(); + + if (!IsVisibleArea(projection, + a.boundingBox, + borderWidth/2.0)) { + return false; + } + + // Collect possible clippings. We only take into account inner rings of the next level + // that do not have a type and thus act as a clipping region. If a inner ring has a type, + // we currently assume that it does not have alpha and paints over its region and clipping is + // not required. + area.VisitClippingRings(i, [&a, &coordRanges](size_t j, const Area::Ring &, const TypeInfoRef &type) -> bool { + if (type->GetIgnore() && coordRanges[j].IsValid()) { + a.clippings.push_back(coordRanges[j]); + } + + return true; + }); + + a.ref=area.GetObjectFileRef(); + a.type=type; + a.buffer=&ring.GetFeatureValueBuffer(); + a.fillStyle=fillStyle; + a.borderStyle=borderStyle; + a.coordRange=coordRanges[i]; + + areaData.push_back(a); + + for (size_t idx=borderStyleIndex; + idxGetOffset()!=0.0) { + offset+=GetProjectedWidth(projection, + borderStyle->GetOffset()); + } + + if (borderStyle->GetDisplayOffset()!=0.0) { + offset+=projection.ConvertWidthToPixel(borderStyle->GetDisplayOffset()); + } + + if (offset!=0.0) { + range=coordBuffer.GenerateParallelWay(range, + offset); + } + + // Add a copy of the AreaData definition without the buffer and the fill but only the border + + a.ref=area.GetObjectFileRef(); + a.type=type; + a.buffer=nullptr; + a.fillStyle=nullptr; + a.borderStyle=borderStyle; + a.coordRange=range; + + areaData.push_back(a); + } + + return true; + } + void MapPainter::PrepareArea(const StyleConfig& styleConfig, const Projection& projection, const MapParameter& parameter, @@ -1343,121 +1404,17 @@ namespace osmscout { } } - area->VisitRings([&](size_t i, const Area::Ring &ring, const TypeInfoRef &type) -> bool { - - if (type->GetIgnore()) { - // clipping inner ring, we will not render it, but still go deeper, - // there may be nested outer rings - return true; - } - - if (!td[i].IsValid()) { - return false; // ring was skipped or reduced to single point - } - - FillStyleRef fillStyle; - std::vector borderStyles; - BorderStyleRef borderStyle; - - fillStyle=styleConfig.GetAreaFillStyle(type, - ring.GetFeatureValueBuffer(), - projection); - - FillStyleProcessorRef fillProcessor=parameter.GetFillStyleProcessor(ring.GetType()->GetIndex()); - - if (fillProcessor) { - fillStyle=fillProcessor->Process(ring.GetFeatureValueBuffer(), - fillStyle); - } - - styleConfig.GetAreaBorderStyles(type, - ring.GetFeatureValueBuffer(), - projection, - borderStyles); - - if (!fillStyle && borderStyles.empty()) { - return false; - } - - size_t borderStyleIndex=0; - - if (!borderStyles.empty() && - borderStyles.front()->GetDisplayOffset()==0.0 && - borderStyles.front()->GetOffset()==0.0) { - borderStyle=borderStyles[borderStyleIndex]; - borderStyleIndex++; - } - - AreaData a; - double borderWidth=borderStyle ? borderStyle->GetWidth() : 0.0; - - a.boundingBox=ring.GetBoundingBox(); - a.isOuter = ring.IsOuter(); - - if (!IsVisibleArea(projection, - a.boundingBox, - borderWidth/2.0)) { - return false; - } - - // Collect possible clippings. We only take into account inner rings of the next level - // that do not have a type and thus act as a clipping region. If a inner ring has a type, - // we currently assume that it does not have alpha and paints over its region and clipping is - // not required. - area->VisitClippingRings(i, [&a, &td](size_t j, const Area::Ring &, const TypeInfoRef &type) -> bool { - if (type->GetIgnore() && td[j].IsValid()) { - PolyData data; - - data.transStart=td[j].GetStart(); - data.transEnd=td[j].GetEnd(); - - a.clippings.push_back(data); - } - return true; - }); - - a.ref=area->GetObjectFileRef(); - a.type=type; - a.buffer=&ring.GetFeatureValueBuffer(); - a.fillStyle=fillStyle; - a.borderStyle=borderStyle; - a.coordRange=td[i]; - - areaData.push_back(a); - - for (size_t idx=borderStyleIndex; - idxGetOffset()!=0.0) { - offset+=GetProjectedWidth(projection, - borderStyle->GetOffset()); - } - - if (borderStyle->GetDisplayOffset()!=0.0) { - offset+=projection.ConvertWidthToPixel(borderStyle->GetDisplayOffset()); - } - - if (offset!=0.0) { - range=coordBuffer.GenerateParallelWay(range, - offset); - } - - a.ref=area->GetObjectFileRef(); - a.type=type; - a.buffer=nullptr; - a.fillStyle=nullptr; - a.borderStyle=borderStyle; - a.coordRange=range; - - areaData.push_back(a); - } - return true; + area->VisitRings([this,&styleConfig,&projection,¶meter,&td,&area](size_t i, + const Area::Ring& ring, + const TypeInfoRef& type)->bool { + return PrepareAreaRing(styleConfig, + projection, + parameter, + td, + *area, + ring, + i, + type); }); } diff --git a/libosmscout/include/osmscout/util/Projection.h b/libosmscout/include/osmscout/util/Projection.h index 5b7efc7a3..823a4f02c 100644 --- a/libosmscout/include/osmscout/util/Projection.h +++ b/libosmscout/include/osmscout/util/Projection.h @@ -325,6 +325,16 @@ namespace osmscout { virtual bool GeoToPixel(const GeoCoord& coord, double& x, double& y) const = 0; + /** + * Converts a valid GeoBox to its on screen pixel coordinates + * + * Return true on success, + * false if given coordinate is not valid for this projection. + */ + bool BoundingBoxToPixel(const GeoBox& boundingBox, + double& xMin, double& yMin, + double& xMax, double& yMax) const; + protected: virtual void GeoToPixel(const BatchTransformer& transformData) const = 0; diff --git a/libosmscout/src/osmscout/util/Projection.cpp b/libosmscout/src/osmscout/util/Projection.cpp index 50d1e7a38..1460f7117 100644 --- a/libosmscout/src/osmscout/util/Projection.cpp +++ b/libosmscout/src/osmscout/util/Projection.cpp @@ -59,6 +59,78 @@ namespace osmscout { static const double gradtorad=2*M_PI/360; + bool Projection::BoundingBoxToPixel(const GeoBox& boundingBox, + double& xMin, + double& yMin, + double& xMax, + double& yMax) const + { + assert(boundingBox.IsValid()); + + double x; + double y; + + if (!GeoToPixel(boundingBox.GetMinCoord(), + x, + y)) { + return false; + } + + xMin=x; + xMax=x; + yMin=y; + yMax=y; + + if (!GeoToPixel(boundingBox.GetMaxCoord(), + x, + y)) { + return false; + } + + xMin=std::min(xMin, + x); + xMax=std::max(xMax, + x); + yMin=std::min(yMin, + y); + yMax=std::max(yMax, + y); + + if (!GeoToPixel(GeoCoord(boundingBox.GetMinLat(), + boundingBox.GetMaxLon()), + x, + y)) { + return false; + } + + xMin=std::min(xMin, + x); + xMax=std::max(xMax, + x); + yMin=std::min(yMin, + y); + yMax=std::max(yMax, + y); + + if (!GeoToPixel(GeoCoord(boundingBox.GetMaxLat(), + boundingBox.GetMinLon()), + x, + y)) { + return false; + } + + xMin=std::min(xMin, + x); + xMax=std::max(xMax, + x); + yMin=std::min(yMin, + y); + yMax=std::max(yMax, + y); + + return true; + } + bool MercatorProjection::Set(const GeoCoord& coord, double angle, const Magnification& magnification,