Skip to content

OEP7: Mixed Dimension Geometry Support

Hans Loeblich edited this page Aug 5, 2021 · 1 revision

OpenSCAD currently operates on two types of geometry: 2D solids and 3D solids.

There are other kinds of geometry that would be useful to support, which can be represented with a pair of dimensions:
mD-in-nD where m is the dimensionality of the geometry itself, n is the dimension of space which it is embedded in. Additionally: m <= n which implies that lower dimension shapes can be embedded in higher dimensional space.

As a quick example, probably the most discussed aspect of this is 2D-in-3D geometry or "oriented 2d shapes" as mentioned in OEP1: Generalized-extrusion-module (also see PR #2796). These could be created by applying 3D transformations to 2D geometry. (e.g. translating away from z0 plane: translate([0,0,z]) some2DGeometry();)

List of all potential geometries

Geometry Dimensions Description Usage examples and notes
0D-in-2D 2D Point set Mainly useful for 2D hull(), possibly minkowski()
0D-in-3D 3D Point set Mainly useful for 3D hull(), possibly minkowski()
1D-in-2D Lines and paths in 2D space For building up 2D shapes, can be offset() to create stroked lines as in SVG
1D-in-3D Lines and paths in 3D space For generalized extruding/lofting along a path
2D-in-2D 2D Solid "Plain old" 2D Solid Geometry, already supported
2D-in-3D Planar 2D Geometry in 3D Space Can be used as the "slices" in a loft operation
2D*-in-3D Non-planar, non-closed 3D surface Maybe useful for creating and stitching NURBS/Bezier patches if support for those is ever added. This type and the one above would be the only case where a dimension pair is not enough to fully describe the difference between types. Not yet sure the best way to represent that.
3D-in-3D 3D Solid "Plain old" 3D Solid Geometry, already supported

Visualization

Since OpenSCAD is still meant to model solid geometries (2D-in-2D and 3D-in-3D), only those should remain valid as top-level, exportable shapes. Other geometry types would be valid only as intermediates for generating valid solids.

However, for user convenience we may want to allow at least Preview of some or all of the proposed mixed-dimension geometries.
Currently, 2D-in-3D already does preview in this way, but that is mostly a coincidental quirk of how the OpenCSG 2D implementation works. Also, when such transformed 2D shapes get Rendered, they end up being projected down to the XY plane.

General Implementation Notes

The base Geometry class declares virtual unsigned int getDimension() const It currently returns 2 or 3, but would be better changed to return an enum representing the above dimension pairs.

Operations over combinations of different geometry dimensions

Some types of operations could be applicable over combinations of multiple geometry dimension types.

  • The usual affine transformations: translate(...), rotate(...), scale(...), resize(...), mirror(...), multmatrix(...) could all be applicable to combinations of various geometry dimension types.

  • hull() is only concerned with the constituent vertices of its input geometry, so any mD-in-nD type, or any combination of types could be considered valid inputs of hull.

  • minkowski() could also potentially sum over any combination of geometry dimensions. For example:

    minkowski() {
      square(100, center=true);
      sphere(d=10);
    }
    // would be expected to generate the same geometry as:
    hull() for(p=[[-50,-50],[50,-50],[-50,50],[50,50]])
      translate(p) sphere(d=10);
    
  • projection() could be considered applicable to any combination of mD-in-3D inputs, resulting in mD-in-2D output

For any combination of mixed dimension geometries, the result inputs of mD-in-nD and pD-in-qD should be max(m,p)D-in-max(n,q)D If geometries in 2D space are mixed with those in 3D space then z=0 can be implied.

0D geometries

Suggested primitive module signatures:

point2(x,y);
point2([x,y]);
points2([ [x0,y0], [x1,y1], ... ]);

point3(x,y,z);
point3([x,y,z]);
points3([ [x0,y0,z0], [x1,y1,z1], ... ]);

Alternatively the space-dimension of point2,point3, and points2,points3 could be implied from the provided arguments,
so the primitives could be merged/overloaded as point(...) and points(...).

Operations on 0D geometries

  • hull() is probably the most practical use case for point sets, as a convenience (see #3632 ).
    For 0D-in-3D, this would avoid the need to manually define polyhedron faces with correct winding, as long as the desired shape is convex.
    For 0D-in-2D similarly would allow hull with no regard to the order of points being input.

  • union(), difference(), and intersection() over point sets can be trivially implemented as the typical operations from the algebra of sets.

  • minkowski() of any geometry with a set of points would be a sort of alternate/shorthand equivalent of translating the shape to each point:

    points_vector = [ ... ]; // for 2D or 3D points
    minkowski() {
      points(points_vector);
      some_shape(); // for 2D or 3D shape
    }
    // would be same as 
    union() {
      for(p = points_vector)
        translate(p)
        some_shape(); // for 2D or 3D shape
    }
    

Other operations with less or questionable usefulness

  • color(...) maybe applicable if points are made visualizable.
  • linear_extrude(...) could transform points into vertical lines (or diagonal lines with scale argument, helical paths with twist argument)
  • rotate_extrude(...) could transform points into closed circular paths, or partial arc paths with angle parameter
  • offset(r) could transform 2D points into 2D-in-2D circles, or 3D points into 2D-in-3D circles.
  • offset(delta, chamfer) could transform 2D points into 2D-in-2D squares, or 3D points into 2D-in-3D squares (octagons with chamfer=true?).
  • projection(cut=false) could be used to convert 3D points to 2D, discarding z-component
  • projection(cut=true) could be used to filter down points to just those with z = 0

1D-in-2D geometries

AKA paths in 2D.
One of the main ideas for this would be to support circular, elliptical, and bezier curves as primitives, in a way that would e.g. allow an SVG import, then export without any loss of information/scalability.
The viewport Preview/Render could still make use of $fs, $fa for visualizing, but the curves would keep their metadata without being converted to "polylines" for export formats which support such curves. This could also be applied text() fonts usage of bezier curves, providing the possibility of text and SVG being convertible to native OpenSCAD CSG format.

New primitives should be analogous to SVG Path Data commands

path() {
  move_to([x,y]);
  // TODO fill in parameter details for module signatures
  line_to(...)
  arc_to(...)
  bezier_quadratic(...)
  bezier_cubic(...)
  close_path(...);
}

1D-in-3D geometries

Paths in 3D, could overload same primitive modules as 2D paths, by simply providing z-components.

2D-in-2D geometries

Already implemented, no particular change needed.

2D-in-3D geometries

TO BE WRITTEN

2D*-in-3D geometries

TO BE WRITTEN

3D-in-3D geometries

Already implemented, no particular change needed.

Clone this wiki locally