Skip to content

Commit a8613c1

Browse files
authored
fix: Make JsonSurfacesWriter work with ConvexPolygonBounds (#5466)
Before PR [#5195](#5195), `SurfaceJsonConverter::toJson` worked for any SurfaceBounds subclass. PR #5195 introduced the type-based TypeDispatcher, populated by `Config::defaultConfig()` in `Plugins/Json/src/SurfaceJsonConverter.cpp`. The default registration covers all bounds but not `ConvexPolygonBounds<N>`. The dispatcher then throws the error (`TypeDispatcher.hpp`:132–135) "RuntimeError: No function registered for type: Acts::ConvexPolygonBounds<4>"). The Fix: 1) Added `#include "Acts/Surfaces/ConvexPolygonBounds.hpp"` 2) Added a `getSurfaceBoundsKind<>` branch for `ConvexPolygonBoundsBase` returning "ConvexPolygon" 3) Registered `surfaceBoundsToJsonT<ConvexPolygonBoundsBase>` in `Config::defaultConfig()` 4) Registered "PlaneConvexPolygon" decoder. Example from resulting .json: <img width="425" height="571" alt="image" src="https://github.com/user-attachments/assets/93494ea2-7680-4d40-8ca8-9c149f248b8e" />
1 parent 80e6a25 commit a8613c1

1 file changed

Lines changed: 44 additions & 0 deletions

File tree

Plugins/Json/src/SurfaceJsonConverter.cpp

Lines changed: 44 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -11,6 +11,7 @@
1111
#include "Acts/Surfaces/AnnulusBounds.hpp"
1212
#include "Acts/Surfaces/ConeBounds.hpp"
1313
#include "Acts/Surfaces/ConeSurface.hpp"
14+
#include "Acts/Surfaces/ConvexPolygonBounds.hpp"
1415
#include "Acts/Surfaces/CylinderBounds.hpp"
1516
#include "Acts/Surfaces/CylinderSurface.hpp"
1617
#include "Acts/Surfaces/DiamondBounds.hpp"
@@ -60,6 +61,11 @@ std::string getSurfaceBoundsKind() {
6061
return "Cone";
6162
} else if (std::is_same_v<bounds_t, Acts::LineBounds>) {
6263
return "Line";
64+
} else if (std::is_same_v<bounds_t, Acts::ConvexPolygonBoundsBase>) {
65+
// Single kind for every Acts::ConvexPolygonBounds<N> specialization
66+
// (including PolygonDynamic), routed via the abstract base class so the
67+
// TypeDispatcher only needs one registration.
68+
return "ConvexPolygon";
6369
} else if (std::is_same_v<bounds_t, Acts::SurfaceBounds>) {
6470
return "DefaultBounds";
6571
} else if (std::is_same_v<bounds_t, Acts::InfiniteBounds>) {
@@ -225,6 +231,16 @@ Acts::SurfaceJsonConverter::Config::defaultConfig() {
225231
cfg.surfaceBoundsEncoder.registerFunction(surfaceBoundsToJsonT<LineBounds>);
226232
cfg.surfaceBoundsEncoder.registerFunction(
227233
surfaceBoundsToJsonT<InfiniteBounds>);
234+
// ConvexPolygonBounds is templated on the vertex count N. Registering the
235+
// abstract ConvexPolygonBoundsBase lets a single encoder handle every
236+
// specialization (ConvexPolygonBounds<3>, <4>, <6>, ..., <PolygonDynamic>);
237+
// the runtime dynamic_cast inside TypeDispatcher resolves them all to the
238+
// same handler. This fixes the regression introduced by PR #5195 where TGeo
239+
// shapes that produce ConvexPolygonBounds<4> (e.g. TGeoTrap / TGeoArb8) made
240+
// the JsonSurfacesWriter throw "No function registered for type:
241+
// Acts::ConvexPolygonBounds<4>".
242+
cfg.surfaceBoundsEncoder.registerFunction(
243+
surfaceBoundsToJsonT<ConvexPolygonBoundsBase>);
228244

229245
// Decoders
230246
cfg.surfaceDecoder.registerKind(
@@ -242,6 +258,34 @@ Acts::SurfaceJsonConverter::Config::defaultConfig() {
242258
cfg.surfaceDecoder.registerKind(
243259
getSurfaceKind<PlaneSurface>() + getSurfaceBoundsKind<InfiniteBounds>(),
244260
surfaceFromJsonT<PlaneSurface>);
261+
// Custom decoder for ConvexPolygonBounds: the number of vertices is encoded
262+
// only via the size of the "values" array (2 doubles per vertex), so we
263+
// build a dynamically-sized polygon. The kind string ("PlaneConvexPolygon")
264+
// is the same one the encoder writes, since getSurfaceBoundsKind returns
265+
// "ConvexPolygon" for any ConvexPolygonBounds<N>.
266+
cfg.surfaceDecoder.registerKind(
267+
getSurfaceKind<PlaneSurface>() +
268+
getSurfaceBoundsKind<ConvexPolygonBoundsBase>(),
269+
[](const nlohmann::json& j) -> std::shared_ptr<Surface> {
270+
Transform3 sTransform =
271+
Transform3JsonConverter::fromJson(j["transform"]);
272+
std::vector<double> bVector = j["bounds"]["values"];
273+
if (bVector.size() < 6 || bVector.size() % 2 != 0) {
274+
throw std::invalid_argument(
275+
"Invalid ConvexPolygonBounds 'values' array: need an even "
276+
"number of entries (>= 6) encoding at least 3 (x, y) vertices");
277+
}
278+
std::vector<Vector2> vertices;
279+
vertices.reserve(bVector.size() / 2);
280+
for (std::size_t i = 0; i < bVector.size(); i += 2) {
281+
vertices.emplace_back(bVector[i], bVector[i + 1]);
282+
}
283+
auto sBounds =
284+
std::make_shared<const ConvexPolygonBounds<PolygonDynamic>>(
285+
vertices);
286+
return Surface::makeShared<PlaneSurface>(sTransform,
287+
std::move(sBounds));
288+
});
245289

246290
cfg.surfaceDecoder.registerKind(
247291
getSurfaceKind<DiscSurface>() + getSurfaceBoundsKind<AnnulusBounds>(),

0 commit comments

Comments
 (0)