233 lines
7.5 KiB
C++
233 lines
7.5 KiB
C++
#include <CesiumAsync/AsyncSystem.h>
|
|
#include <CesiumAsync/IAssetAccessor.h>
|
|
#include <CesiumGeospatial/CartographicPolygon.h>
|
|
#include <CesiumGeospatial/Ellipsoid.h>
|
|
#include <CesiumGeospatial/GlobeRectangle.h>
|
|
#include <CesiumGeospatial/Projection.h>
|
|
#include <CesiumGltf/ImageAsset.h>
|
|
#include <CesiumRasterOverlays/Library.h>
|
|
#include <CesiumRasterOverlays/RasterOverlay.h>
|
|
#include <CesiumRasterOverlays/RasterOverlayTile.h>
|
|
#include <CesiumRasterOverlays/RasterOverlayTileProvider.h>
|
|
#include <CesiumRasterOverlays/RasterizedPolygonsOverlay.h>
|
|
#include <CesiumUtility/Color.h>
|
|
#include <CesiumUtility/CreditSystem.h>
|
|
#include <CesiumUtility/IntrusivePointer.h>
|
|
#include <CesiumVectorData/VectorRasterizer.h>
|
|
#include <CesiumVectorData/VectorStyle.h>
|
|
|
|
#include <glm/common.hpp>
|
|
#include <glm/ext/vector_double2.hpp>
|
|
#include <spdlog/fwd.h>
|
|
|
|
#include <cstddef>
|
|
#include <cstdint>
|
|
#include <memory>
|
|
#include <optional>
|
|
#include <string>
|
|
#include <vector>
|
|
|
|
using namespace CesiumGeometry;
|
|
using namespace CesiumGeospatial;
|
|
using namespace CesiumUtility;
|
|
|
|
namespace CesiumRasterOverlays {
|
|
namespace {
|
|
void rasterizePolygons(
|
|
LoadedRasterOverlayImage& loaded,
|
|
const CesiumGeospatial::GlobeRectangle& rectangle,
|
|
const CesiumGeospatial::Ellipsoid& ellipsoid,
|
|
const glm::dvec2& textureSize,
|
|
const std::vector<CartographicPolygon>& cartographicPolygons,
|
|
bool invertSelection) {
|
|
|
|
CesiumGltf::ImageAsset& image = loaded.pImage.emplace();
|
|
|
|
uint8_t insideColor;
|
|
uint8_t outsideColor;
|
|
|
|
if (invertSelection) {
|
|
insideColor = 0;
|
|
outsideColor = 0xff;
|
|
} else {
|
|
insideColor = 0xff;
|
|
outsideColor = 0;
|
|
}
|
|
|
|
// create a 1x1 mask if the rectangle is completely inside a polygon
|
|
if (CartographicPolygon::rectangleIsWithinPolygons(
|
|
rectangle,
|
|
cartographicPolygons)) {
|
|
loaded.moreDetailAvailable = false;
|
|
image.width = 1;
|
|
image.height = 1;
|
|
image.channels = 1;
|
|
image.bytesPerChannel = 1;
|
|
image.pixelData.resize(1, std::byte{insideColor});
|
|
return;
|
|
}
|
|
|
|
bool completelyOutsidePolygons = true;
|
|
for (const CartographicPolygon& selection : cartographicPolygons) {
|
|
const std::optional<CesiumGeospatial::GlobeRectangle>& boundingRectangle =
|
|
selection.getBoundingRectangle();
|
|
|
|
if (boundingRectangle &&
|
|
rectangle.computeIntersection(*boundingRectangle)) {
|
|
completelyOutsidePolygons = false;
|
|
break;
|
|
}
|
|
}
|
|
|
|
// create a 1x1 mask if the rectangle is completely outside all polygons
|
|
if (completelyOutsidePolygons) {
|
|
loaded.moreDetailAvailable = false;
|
|
image.width = 1;
|
|
image.height = 1;
|
|
image.channels = 1;
|
|
image.bytesPerChannel = 1;
|
|
image.pixelData.resize(1, std::byte{outsideColor});
|
|
return;
|
|
}
|
|
|
|
// create source image
|
|
loaded.moreDetailAvailable = true;
|
|
image.width = int32_t(glm::round(textureSize.x));
|
|
image.height = int32_t(glm::round(textureSize.y));
|
|
image.channels = 4;
|
|
image.bytesPerChannel = 1;
|
|
image.pixelData.resize(
|
|
size_t(image.width * image.height * 4),
|
|
std::byte{outsideColor});
|
|
|
|
CesiumVectorData::VectorRasterizer rasterizer(
|
|
rectangle,
|
|
loaded.pImage,
|
|
0,
|
|
ellipsoid);
|
|
rasterizer.clear(CesiumUtility::Color{outsideColor, 0x00, 0x00, 0xff});
|
|
|
|
CesiumVectorData::PolygonStyle insideStyle{
|
|
CesiumVectorData::ColorStyle{
|
|
CesiumUtility::Color{insideColor, 0x00, 0x00, 0xff}},
|
|
std::nullopt};
|
|
for (const CartographicPolygon& selection : cartographicPolygons) {
|
|
rasterizer.drawPolygon(selection, insideStyle);
|
|
}
|
|
|
|
rasterizer.finalize();
|
|
// Convert RGBA32 -> R8
|
|
image.changeNumberOfChannels(1);
|
|
}
|
|
} // namespace
|
|
|
|
class CESIUMRASTEROVERLAYS_API RasterizedPolygonsTileProvider final
|
|
: public RasterOverlayTileProvider {
|
|
|
|
private:
|
|
std::vector<CartographicPolygon> _polygons;
|
|
bool _invertSelection;
|
|
|
|
public:
|
|
RasterizedPolygonsTileProvider(
|
|
const IntrusivePointer<const RasterOverlay>& pOwner,
|
|
const CesiumAsync::AsyncSystem& asyncSystem,
|
|
const std::shared_ptr<CesiumAsync::IAssetAccessor>& pAssetAccessor,
|
|
const std::shared_ptr<IPrepareRasterOverlayRendererResources>&
|
|
pPrepareRendererResources,
|
|
const std::shared_ptr<spdlog::logger>& pLogger,
|
|
const CesiumGeospatial::Projection& projection,
|
|
const std::vector<CartographicPolygon>& polygons,
|
|
bool invertSelection)
|
|
: RasterOverlayTileProvider(
|
|
pOwner,
|
|
asyncSystem,
|
|
pAssetAccessor,
|
|
nullptr,
|
|
std::nullopt,
|
|
pPrepareRendererResources,
|
|
pLogger,
|
|
projection,
|
|
// computeCoverageRectangle(projection, polygons)),
|
|
projectRectangleSimple(
|
|
projection,
|
|
CesiumGeospatial::GlobeRectangle::MAXIMUM)),
|
|
_polygons(polygons),
|
|
_invertSelection(invertSelection) {}
|
|
|
|
virtual CesiumAsync::Future<LoadedRasterOverlayImage>
|
|
loadTileImage(const RasterOverlayTile& overlayTile) override {
|
|
// Choose the texture size according to the geometry screen size and raster
|
|
// SSE, but no larger than the maximum texture size.
|
|
const RasterOverlayOptions& options = this->getOwner().getOptions();
|
|
glm::dvec2 textureSize = glm::min(
|
|
overlayTile.getTargetScreenPixels() / options.maximumScreenSpaceError,
|
|
glm::dvec2(options.maximumTextureSize));
|
|
|
|
return this->getAsyncSystem().runInWorkerThread(
|
|
[&polygons = this->_polygons,
|
|
invertSelection = this->_invertSelection,
|
|
projection = this->getProjection(),
|
|
rectangle = overlayTile.getRectangle(),
|
|
textureSize]() -> LoadedRasterOverlayImage {
|
|
const CesiumGeospatial::GlobeRectangle tileRectangle =
|
|
CesiumGeospatial::unprojectRectangleSimple(projection, rectangle);
|
|
|
|
LoadedRasterOverlayImage result;
|
|
result.rectangle = rectangle;
|
|
|
|
rasterizePolygons(
|
|
result,
|
|
tileRectangle,
|
|
getProjectionEllipsoid(projection),
|
|
textureSize,
|
|
polygons,
|
|
invertSelection);
|
|
|
|
return result;
|
|
});
|
|
}
|
|
};
|
|
|
|
RasterizedPolygonsOverlay::RasterizedPolygonsOverlay(
|
|
const std::string& name,
|
|
const std::vector<CartographicPolygon>& polygons,
|
|
bool invertSelection,
|
|
const CesiumGeospatial::Ellipsoid& ellipsoid,
|
|
const CesiumGeospatial::Projection& projection,
|
|
const RasterOverlayOptions& overlayOptions)
|
|
: RasterOverlay(name, overlayOptions),
|
|
_polygons(polygons),
|
|
_invertSelection(invertSelection),
|
|
_ellipsoid(ellipsoid),
|
|
_projection(projection) {}
|
|
|
|
RasterizedPolygonsOverlay::~RasterizedPolygonsOverlay() = default;
|
|
|
|
CesiumAsync::Future<RasterOverlay::CreateTileProviderResult>
|
|
RasterizedPolygonsOverlay::createTileProvider(
|
|
const CesiumAsync::AsyncSystem& asyncSystem,
|
|
const std::shared_ptr<CesiumAsync::IAssetAccessor>& pAssetAccessor,
|
|
const std::shared_ptr<CreditSystem>& /*pCreditSystem*/,
|
|
const std::shared_ptr<IPrepareRasterOverlayRendererResources>&
|
|
pPrepareRendererResources,
|
|
const std::shared_ptr<spdlog::logger>& pLogger,
|
|
CesiumUtility::IntrusivePointer<const RasterOverlay> pOwner) const {
|
|
|
|
pOwner = pOwner ? pOwner : this;
|
|
|
|
return asyncSystem.createResolvedFuture<CreateTileProviderResult>(
|
|
IntrusivePointer<RasterOverlayTileProvider>(
|
|
new RasterizedPolygonsTileProvider(
|
|
pOwner,
|
|
asyncSystem,
|
|
pAssetAccessor,
|
|
pPrepareRendererResources,
|
|
pLogger,
|
|
this->_projection,
|
|
this->_polygons,
|
|
this->_invertSelection)));
|
|
}
|
|
|
|
} // namespace CesiumRasterOverlays
|