Skip to content

Commit 2d6cb7a

Browse files
authored
Merge pull request #1229 from CesiumGS/vector-random-fix
Fix `ColorMode::Random` producing different results for each vector overlay tile rasterized
2 parents ca90e8f + 32e5fdf commit 2d6cb7a

6 files changed

Lines changed: 67 additions & 19 deletions

File tree

CHANGES.md

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,7 @@
88
- `ViewUpdateResult` now holds pointers to const `Tile` instances.
99
- The `slowlyGetCurrentStates` and `slowlyGetPreviousStates` methods of `TreeTraversalState` now return the state map with a raw pointer to a constant node as the key, even if the node pointer type is a smart pointer.
1010
- `DebugTileStateDatabase::recordTileState` now expects the states to be provided as `std::unordered_map<const Tile*, TileSelectionState>` instead of `std::unordered_map<IntrusivePointer<Tile>, TileSelectionState>`.
11+
- `VectorRasterizer::drawPolyline` now takes a `std::vector` instead of a `std::span`.
1112

1213
##### Additions :tada:
1314

@@ -19,6 +20,7 @@
1920
##### Fixes :wrench:
2021

2122
- Fixed a bug in `Tileset::updateViewGroupOffline` that would cause it to get stuck in an endless loop when invoked with no frustums.
23+
- Fixed `ColorMode::Random` in `VectorStyle` producing different results each time a raster overlay tile was rendered.
2224
- Fixed a bug in `IonRasterOverlay` that would cause unnecessary extra use of Bing Maps sessions when manually reloading the raster overlay after an expired token was automatically refreshed.
2325
- Fixed a bug that could lead to a crash when using raster overlays with tilesets that use "external tilesets", such as Google Photorealistic 3D Tiles.
2426

CesiumVectorData/include/CesiumVectorData/VectorRasterizer.h

Lines changed: 2 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -75,9 +75,8 @@ class VectorRasterizer {
7575
* should be specified in degrees.
7676
* @param style The \ref LineStyle to use when drawing the polyline.
7777
*/
78-
void drawPolyline(
79-
const std::span<const glm::dvec3>& points,
80-
const LineStyle& style);
78+
void
79+
drawPolyline(const std::vector<glm::dvec3>& points, const LineStyle& style);
8180

8281
/**
8382
* @brief Rasterizes a `GeoJsonObject` to the canvas.

CesiumVectorData/include/CesiumVectorData/VectorStyle.h

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -40,8 +40,12 @@ struct ColorStyle {
4040
* For `ColorMode::Normal`, this just returns the value of `color`. For
4141
* `ColorMode::Random`, this returns a randomized value obtained based on
4242
* the rules described in \ref ColorMode.
43+
*
44+
* @param randomColorSeed The seed for the random color to be generated, if
45+
* `colorMode` is set to `Random`. The same color will always be returned for
46+
* a given seed, but nearby seeds will not usually return nearby colors.
4347
*/
44-
CesiumUtility::Color getColor() const;
48+
CesiumUtility::Color getColor(size_t randomColorSeed = 0) const;
4549
};
4650

4751
/** @brief The mode to use when interpreting a given line width. */

CesiumVectorData/src/VectorRasterizer.cpp

Lines changed: 12 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -24,7 +24,6 @@
2424
#include <cmath>
2525
#include <cstddef>
2626
#include <cstdint>
27-
#include <span>
2827
#include <vector>
2928

3029
using namespace CesiumGeospatial;
@@ -58,6 +57,10 @@ void setStrokeWidth(
5857
(bounds.computeWidth() * ellipsoid.getRadii().x));
5958
}
6059
}
60+
61+
template <typename T> size_t seedForObject(const T& object, size_t base) {
62+
return base ^ reinterpret_cast<size_t>(&object);
63+
}
6164
} // namespace
6265

6366
VectorRasterizer::VectorRasterizer(
@@ -116,7 +119,7 @@ void VectorRasterizer::drawPolygon(
116119
this->_context.fillPolygon(
117120
vertices.data(),
118121
vertices.size(),
119-
BLRgba32(style.fill->getColor().toRgba32()));
122+
BLRgba32(style.fill->getColor(seedForObject(polygon, 13)).toRgba32()));
120123
}
121124

122125
if (style.outline) {
@@ -128,7 +131,8 @@ void VectorRasterizer::drawPolygon(
128131
this->_context.strokePolygon(
129132
vertices.data(),
130133
vertices.size(),
131-
BLRgba32(style.outline->getColor().toRgba32()));
134+
BLRgba32(
135+
style.outline->getColor(seedForObject(polygon, 31)).toRgba32()));
132136
}
133137
}
134138

@@ -157,7 +161,7 @@ void VectorRasterizer::drawPolygon(
157161
this->_context.fillPolygon(
158162
vertices.data(),
159163
vertices.size(),
160-
BLRgba32(style.fill->getColor().toRgba32()));
164+
BLRgba32(style.fill->getColor(seedForObject(polygon, 13)).toRgba32()));
161165
}
162166

163167
if (style.outline) {
@@ -169,12 +173,13 @@ void VectorRasterizer::drawPolygon(
169173
this->_context.strokePolygon(
170174
vertices.data(),
171175
vertices.size(),
172-
BLRgba32(style.outline->getColor().toRgba32()));
176+
BLRgba32(
177+
style.outline->getColor(seedForObject(polygon, 31)).toRgba32()));
173178
}
174179
}
175180

176181
void VectorRasterizer::drawPolyline(
177-
const std::span<const glm::dvec3>& points,
182+
const std::vector<glm::dvec3>& points,
178183
const LineStyle& style) {
179184
if (this->_finalized) {
180185
return;
@@ -197,7 +202,7 @@ void VectorRasterizer::drawPolyline(
197202
this->_context.strokePolyline(
198203
vertices.data(),
199204
vertices.size(),
200-
BLRgba32(style.getColor().toRgba32()));
205+
BLRgba32(style.getColor(seedForObject(points, 31)).toRgba32()));
201206
}
202207

203208
void VectorRasterizer::drawGeoJsonObject(

CesiumVectorData/src/VectorStyle.cpp

Lines changed: 12 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -1,26 +1,30 @@
11
#include <CesiumUtility/Color.h>
22
#include <CesiumVectorData/VectorStyle.h>
33

4+
#include <cstddef>
45
#include <cstdint>
6+
#include <functional>
57
#include <optional>
6-
#include <random>
78

89
using namespace CesiumUtility;
910

1011
namespace CesiumVectorData {
11-
Color ColorStyle::getColor() const {
12+
Color ColorStyle::getColor(size_t randomColorSeed) const {
1213
if (this->colorMode == ColorMode::Normal) {
1314
return this->color;
1415
}
1516

16-
std::random_device r;
17-
std::mt19937 mt(r());
18-
std::uniform_real_distribution<float> dist(0.0f, 1.0f);
17+
std::hash<size_t> hash{};
18+
size_t h = hash(randomColorSeed);
19+
20+
float r = uint8_t(h & 0xFF) / 255.0f;
21+
float g = uint8_t((h >> 8) & 0xFF) / 255.0f;
22+
float b = uint8_t((h >> 16) & 0xFF) / 255.0f;
1923

2024
return Color{
21-
(uint8_t)(dist(mt) * (float)this->color.r),
22-
(uint8_t)(dist(mt) * (float)this->color.g),
23-
(uint8_t)(dist(mt) * (float)this->color.b),
25+
(uint8_t)(r * this->color.r),
26+
(uint8_t)(g * this->color.g),
27+
(uint8_t)(b * this->color.b),
2428
this->color.a};
2529
}
2630
VectorStyle::VectorStyle(const CesiumUtility::Color& color)

CesiumVectorData/test/TestVectorRasterizer.cpp

Lines changed: 34 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -327,6 +327,40 @@ TEST_CASE("VectorRasterizer::rasterize") {
327327
writeImageToTgaFile(*asset, "styling.tga");
328328
checkFilesEqual(dir / "styling.tga", thisDir / "styling.tga");
329329
}
330+
331+
SUBCASE("Random color uses the same color across calls") {
332+
CesiumUtility::IntrusivePointer<CesiumGltf::ImageAsset> asset;
333+
asset.emplace();
334+
asset->width = 1;
335+
asset->height = 1;
336+
asset->channels = 4;
337+
asset->bytesPerChannel = 1;
338+
asset->pixelData.resize(4, std::byte{255});
339+
340+
CartographicPolygon square(std::vector<glm::dvec2>{
341+
glm::dvec2{Math::degreesToRadians(0.0), Math::degreesToRadians(0.0)},
342+
glm::dvec2{Math::degreesToRadians(0.0), Math::degreesToRadians(1.0)},
343+
glm::dvec2{Math::degreesToRadians(1.0), Math::degreesToRadians(1.0)},
344+
glm::dvec2{Math::degreesToRadians(1.0), Math::degreesToRadians(0.0)},
345+
glm::dvec2{Math::degreesToRadians(0.0), Math::degreesToRadians(0.0)}});
346+
347+
VectorStyle style;
348+
style.polygon.fill =
349+
ColorStyle{Color{0xff, 0x00, 0xaa, 0xff}, ColorMode::Random};
350+
351+
VectorRasterizer rasterizer(rect, asset);
352+
rasterizer.drawPolygon(square, style.polygon);
353+
rasterizer.finalize();
354+
355+
const uint32_t writtenColor =
356+
*reinterpret_cast<uint32_t*>(asset->pixelData.data());
357+
VectorRasterizer rasterizer2(rect, asset);
358+
rasterizer2.drawPolygon(square, style.polygon);
359+
rasterizer2.finalize();
360+
361+
CHECK(
362+
*reinterpret_cast<uint32_t*>(asset->pixelData.data()) == writtenColor);
363+
}
330364
}
331365

332366
TEST_CASE("VectorRasterizer::rasterize benchmark" * doctest::skip(true)) {

0 commit comments

Comments
 (0)