@@ -80,6 +80,52 @@ extension Tag: Geometry {
8080 }
8181}
8282
83+ public extension Tag {
84+ /// Reads the individual geometry members associated with this tag and provides them for further composition.
85+ ///
86+ /// This is similar to using the tag directly as geometry, except the tagged definitions are passed to the
87+ /// `reader` closure as separate geometries instead of being unioned first. Each geometry is positioned in the
88+ /// same coordinate system as a direct tag reference, preserving the world-space transform captured when tagged.
89+ ///
90+ /// - Parameter reader: A closure that receives all geometries currently associated with this tag.
91+ /// - Returns: A geometry object resulting from the `reader` closure.
92+ func readingMembers< Output: Dimensionality > (
93+ @GeometryBuilder < Output > _ reader: @Sendable @escaping ( _ members: [ D3 . Geometry ] ) -> Output . Geometry
94+ ) -> Output . Geometry {
95+ TagGeometryReader ( tag: self , reader: reader)
96+ }
97+
98+ /// Applies a transform to each individual geometry member associated with this tag and unions the results.
99+ ///
100+ /// This is a convenience wrapper around `readingMembers` for the common case where every tagged definition should
101+ /// be processed independently.
102+ ///
103+ /// - Parameter transform: A closure called once for each tagged geometry member.
104+ /// - Returns: The union of all geometries returned by `transform`.
105+ func map< Output: Dimensionality > (
106+ @GeometryBuilder < Output > _ transform: @Sendable @escaping ( _ member: D3 . Geometry ) -> Output . Geometry
107+ ) -> Output . Geometry {
108+ readingMembers { members in
109+ for member in members {
110+ transform ( member)
111+ }
112+ }
113+ }
114+ }
115+
116+ internal struct TagGeometryReader < Output: Dimensionality > : Geometry {
117+ let tag : Tag
118+ let reader : @Sendable ( [ D3 . Geometry ] ) -> Output . Geometry
119+
120+ func build( in environment: EnvironmentValues , context: EvaluationContext ) async throws -> Output . BuildResult {
121+ let geometries = environment. buildResults ( for: tag) . map {
122+ $0. transformed ( environment. transform. inverse)
123+ }
124+ return try await context. buildResult ( for: reader ( geometries) , in: environment)
125+ . modifyingElement ( ReferenceState . self) { $0. read ( tag: tag) }
126+ }
127+ }
128+
83129internal struct TagGeometry : Geometry {
84130 let body : any Geometry3D
85131 let tag : Tag
0 commit comments