Closed platypii closed 6 months ago
@platypii sorry for the lack of a review. hopefully, i can play with the new style this weekend.
Just to add a bit more justification for this PR:
One of my goals is to improve things like SVG serialize/deserialize. I want to be able to convert SVG groups into nested sub-arrays of geometries. And then it would be really nice if information was not lost along the way. So for example: 1) Load geometry from SVG, 2) Apply transform
, or extrude
, or offset
, or align
, etc to the nested geometry, 3) Re-export to SVG while still preserving the nested group structure.
Currently that information is lost when any operation is applied to a design because arrays get flattened. This PR attempts to preserve that structure where possible.
@platypii Can you finish these changes? It would be nice to get these into V3.
@z3dev updated PR based on feedback, and added a few more tests to try and make things clearer. Thanks!
This PR contains my suggestions for JSCAD v3 handling of input arrays. Some of these are breaking changes from V2. I tried to follow a couple principles:
align
below.*throws for obviously incorrect geometries, but will incorrectly flatten and return some things like
[[1,2],[3,4]]
Nested Arrays as Groups
I suggest that we preserve nested arrays where it makes sense to do so. This information can be treated like “groups” in svg and other file formats. For operations which return a single geometry, like the booleans, we should still flatten before we apply the operation, but if it makes sense to do so, I propose that we preserve the recursive structure as much as possible.
null/undefined
I suggest that we filter out null-ish values when we do a flatten operation for booleans, and most operations. To make working with nested arrays easier, I added a new util function
coalesce
which combines flatten and filtering out nullish values.Empty arrays
What if a user calls a boolean operation with an empty array, or an array which is empty when flattened? We have three options 1) throw error, but I would prefer not to do this 2) return geom2.create() or geom3.create(), but the problem is that we don’t actually know if it’s intended to be 2D or 3D. I propose that in this case we return undefined, which can be filtered out by other operations using coalesce.
Mix 2D/3D
If you call a boolean between a 2D and 3D geometry, it’s not clear what to return in that case, so we should throw if not all types are the same. However for transforms, and modifiers, it’s okay to mix 2D and 3D. I propose that we apply functions where it makes sense. If an object is nullish, or not a geometry, I suggest we simply map the object to itself and return it in the output. This makes the operation robust against unexpected inputs.
Alignment
One other suggestion is that I believe that align and center operations should respect groupings, and use them when aligning objects rather than flattening. See suggestion from @hjfreyer in #1249. The reason I like this change is that it gives more flexibility to users. In V2, inputs will be flattened regardless of the user's intent. Whereas with this change, users can align groups of objects. The previous behavior can be accessed by setting
options.grouped = true
.Examples
All Submissions: