Class BezierGrid

java.lang.Object
org.bzdev.geom.BezierGrid
All Implemented Interfaces:
Shape3D

public class BezierGrid extends Object implements Shape3D
Class representing a grid of cubic Bézier patches. The patches are specified by providing a rectangular grid of points, some of which may be null. Most of the constructors specify this grid directly. There are two exceptions: The first argument of these two constructorss is a 2D path representing a cross section of a tube or wire, and handles a common special case.

Each element of the grid contains

  • a point on the surface that the grid represents. This point corresponds to the U-V coordinate (0,0), and may be null. It may also be marked as "unfilled" by calling remove(int,int) or remove(int,int,int,int).
  • the intermediate control points for a cubic Bézier curve along the edge from (0,0) to (1, 0), excluding the initial control point. These control points are P10 and P20, where Pij are the control points for the corresponding cubic Bézier patch. The values of these intermediate control points can be explicitly set, although they will be computed if necessary.
  • the intermediate control points for a cubic Bézier curve along the edge from (0,0) to (0, 1), excluding the initial control point. These control points are P01 and P02, where Pij are the control points for the corresponding cubic Bézier patch. The values of these intermediate control points can be explicitly set, although they will be computed if necessary.
  • the four control points P11, P21, P12 and P22. While these control points can be provided explicitly, if these points are not provided a default will be computed.
The remaining control points for the cubic Bézier patch associated with a grid element are provided by the adjacent grid elements. All of these points are stored as double precision numbers that have been rounded to the nearest float value by replacing a value v with (double)(float)v. This is done for consistency with the Surface3D and Model3D classes, and to reduce the impact of floating point errors in computing coordinates. The methods createConnectionsTo(BezierGrid), createConnectionsTo(BezierGrid,int), createConnectionsTo(BezierGrid,int,boolean), createConnectionsTo(BezierGrid,boolean,int...), createConnectionsTo(BezierGrid,int,boolean,int...), and createConnectionsTo(BezierGrid,int,boolean,boolean,int...) have a precondition: except when a loop is being closed (that is, the intermediate control points differ from the grid points), multiple points on a grid must not have the same values. For cases where it is convenient to create grids in which multiple points have the same values, one may be able to use the method subgrid(int,int,int,int) to create a suitable grid. This is useful in some unusual cases such as creating a Möbius strip where to get a closed curve, the surface has to be traversed twice, and a subgrid will produce a shape that is closed.

A grid has two dimensions, with indices (i,j). For an element at indices (i, j), the end points for each edge of the patch are shown in the following table.

 
Starting
(u,v)
Ending
(uv)
Starting
indices
Ending
indices
Edge 0(0,0)(1,0)(i,j)(i+1,j)
Edge 1(1,0)(1,1)(i+1,j)(i+1,j+1)
Edge 2(0,1)(1,1)(i,j+1)(i+1,j+1)
Edge 3(0,0)(0,1)(i,j)(i,j+1)
Edge 2 and Edge 3 are traversed in the opposite direction from the one shown when determining the patch's orientation, which uses the right-hand rule. The implementation stores the control points for Edge 0 and Edge 3 in the element associated with the index (i,j). Adjacent elements are queried to find the remaining edge's control points.

Splines are automatically created to set the shape of each edge, ensuring that adjacent patches share common edges. The knots for these splines have either constant values of i or constant values of j. These splines are controlled by two constructor arguments: uclosed and vclosed:

  • When uclosed is false, the splines with knots at constant values of j cover spans of points that are within the grid and not null.
  • When uclosed is true, the splines with knots at constant values of j also cover spans of points that are within the grid and not null. If none of the elements are null, a cyclic spine is created. Otherwise splines are delimited by null grid points, and the sequence of knots with wrap around if necessary (i.e., a knot at the maximum value of i may be followed by a knot for which i = 0).
  • When vclosed is false, the splines with knots at constant values of i cover spans of points that are within the grid and not null.
  • When vclosed is true, the splines with knots at constant values of i also cover spans of points that are within the grid and not null. If none of the elements are null, a cyclic spine is created. Otherwise splines are delimited by null grid points, and the sequence of knots with wrap around if necessary (i.e., a knot at the maximum value of j may be followed by a knot for which j = 0).
When uclosed is true and for a fixed value of j, the point at the maximum value of i must not be the same as the point at i = 0. Similarly, When vclosed is true and for a fixed value of i, the point at the maximum value of j must not be the same as the point at j = 0. These flags are useful for some common shapes:
  • When one is true, the grid can represent a cylinder or a ring with two boundaries.
When both are true, the grid can represent a torus.

One can partition the grid into regions by giving each point a region ID (by default, points will be in region 0). The splines described above will be split into multiple splines when a region boundary is crossed. This allows the grid to have sharp corners or edges at the region boundaries. A point on one side of a boundary will be connected to a point on the other side by a straight line segment. The methods to create regions are setRegion(int,int,int) and setRegion(int,int,int,int,int).

In addition, users may define additional splines. The additional splines are used to set edges after the automatically generated splines are created, thus overriding those values. The additional splines are used in the order in which they were defined. The methods startSpline(int,int), moveU(int), moveV(int), and endSpline(boolean) are used for configuring these splines.

For example, in order to create the following object,

sphere

one can first create a grid representing a half of a sphere:

        int N = 41; // grid height and width
        int NC = N/2; // grid center point.
        Point3D[][] array1 = new Point3D[N][N];

        double r = 100.0;       // radius of the sphere

        for (int i = 0; i < N; i++) {
            for (int j = 0; j < N; j++) {
                int k = Math.max(Math.abs(i-NC),Math.abs(j-NC));
                double theta = k*(Math.PI/(N-1));
                double x, y, z;
                if (k == 0) {
                  // top of the sphere
                    x = 0.0; y = 0.0; z = r;
                } else {
                  // Each square box around the center of
                  // the grid (in U-V space) represents a
                  // line of constant latitude. Adjacent
                  // vertices along a specific box are
                  // separated by evenly spaced longitude
                  // values.
                    int nanglesHalf = k*4;
                    double delta = Math.PI/(nanglesHalf);
                    double angle;
                    if (i == NC+k) {
                        angle = -(NC-j)*delta;
                    } else if (j == NC-k) {
                        angle = -(NC + 2*k - i)*delta;
                    } else if (i == NC-k) {
                        angle = -((j-NC) + 4*k)*delta;
                    } else if (j == NC+k) {
                        angle = (NC+2*k-i)*delta;
                    } else {
                        throw new Error();
                    }
                    x = r * Math.cos(angle) * Math.sin(theta);
                    y = r * Math.sin(angle) * Math.sin(theta);
                  // the 10.0 shifts the sphere up slightly
                  // along the Z axis
                    z = 10.0 + r * Math.cos(theta);
                }
                array1[i][j] = new Point3D.Double(x, y, z);
            }
        }
        BezierGrid grid1 = new BezierGrid(array1);
 
Note that the value of z for each point adds a constant 10.0 to each value, which translates the grid upwards. After this grid is created, it can be modified by removing the vertices above a specific latitude (note that the area removed has boundary that corresponds to a series of points with a constant latitude).

        grid1.remove(NC-3, NC-3, 6, 6);
 
The half sphere now has a boundary with two components (two distinct continuous, closed paths). For these, we set a user defined spline in order to make sure that splines will be created going through these vertices and that the spline will be a cyclic one (the argument of true for endSpline makes the spline a cyclic spline).

        grid1.startSpline(NC-3, NC-3);
        grid1.moveU(6);
        grid1.moveV(6);
        grid1.moveU(-6);
        grid1.moveV(-6);
        grid1.endSpline(true);

        grid1.startSpline(0,0);
        grid1.moveU(N-1);
        grid1.moveV(N-1);
        grid1.moveU(-(N-1));
        grid1.moveV(-(N-1));
        grid1.endSpline(true);
 
The next step is to create the bottom half of the sphere. A constructor (please see the documentation for BezierGrid(BezierGrid,boolean,UnaryOperator) for restrictions) allows one to reproduce the configuration of an existing grid, with a lambda expression mapping previous vertex locations into new ones:

        BezierGrid grid2 = new BezierGrid(grid1, true, (p) -> {
                double x = p.getX();
                double y = p.getY();
                double z = - p.getZ();
                return new Point3D.Double(x, y, z);
            });
 
The argument true indicates that grid2 should have its orientation reversed compared to grid1. At this point, one can create a surface and append the two grids.

        Surface3D surface = new Surface3D.Double();
        surface.append(grid1);
        surface.append(grid2);
 
The next step is to create an array of grids (it will just contain a single element). This grid will have two vertices in its U direction, and will connect grid1 to grid2. The argument 'false' prevents the grids from being split at spline boundaries, and the two arguments with the value NC-3 are indices of a point on grid1's boundary corresponding to the circular hole in grid1 at the 'top' of its half sphere. Because there are only two vertices in the U direction, the call to createConnectionsTo generates a cylinder. The newly created grid is appended to the surface.

        BezierGrid[] connections =
            grid1.createConnectionsTo(grid2, false, NC-3, NC-3);
        for (BezierGrid g: connections) {
            surface.append(g);
        }
 
Similarly, one can create a second set of grids, this time with 11 vertices in the U direction.

      connections = grid1.createConnectionsTo(grid2, 11, false, 0, 0);
 
In the U direction index 0 and 10 represent V values that match the boundaries at the widest points of the two half spheres (grid1 and grid2). The remaining vertices have to be configured manually. For an example, this is done as follows:

      BezierGrid cgrid = connections[0];
      int limu = cgrid.getUArrayLength() ;
      int limv = cgrid.getVArrayLength();
      for (int j = 0; j < limv; j++) {
        for (int i = 1; i < limu - 1; i++) {
           Point3D p = cgrid.getPoint(0, j);
           double t = ((double)i)/limu;
           double z1 = p.getZ();
           double z2 = cgrid.getPoint(10, j).getZ();
           double z = z1*(1-t) + z2*t;
           double scale = 1.0 + 0.25*Math.sin(Math.PI*t);
           double x = scale*p.getX();
           double y = scale*p.getY();
           cgrid.setPoint(i, j, x, y, z);
        }
      }
        surface.append(cgrid);
 
The result is a 'bulge' connecting the two half spheres, with the bulge using a sinusoidal shape. Finally, one can create a series of images using methods from the p3d package:

      Model3D m3d = new Model3D();
      m3d.append(surface);
      m3d.setTessellationLevel(2);
      m3d.createImageSequence
          (new FileOutputStream("images.isq"),
           "png", 8, 6, 0.0, 0.0, 0.0, false);
 
  • Nested Class Summary

    Nested Classes
    Modifier and Type
    Class
    Description
    static interface 
    Interface for mapping one point in a two or three dimensional space into a point in a three dimensional point, with parameters indicating if the point is a control point.
  • Constructor Summary

    Constructors
    Constructor
    Description
    BezierGrid(double[] sarray, boolean uclosed, double[] tarray, boolean vclosed, boolean linear, RealValuedFunctTwoOps xfunct, RealValuedFunctTwoOps yfunct, RealValuedFunctTwoOps zfunct)
    Constructor using real-valued functions and specifying if the U and V directions are cyclic or not, with possibly a linear constraint for the line segments connecting adjacent points on the grid.
    BezierGrid(double[] sarray, boolean uclosed, double[] tarray, boolean vclosed, RealValuedFunctTwoOps xfunct, RealValuedFunctTwoOps yfunct, RealValuedFunctTwoOps zfunct)
    Constructor using real-valued functions and specifying if the U and V directions are cyclic or not.
    BezierGrid(double[] sarray, double[] tarray, RealValuedFunctTwoOps xfunct, RealValuedFunctTwoOps yfunct, RealValuedFunctTwoOps zfunct)
    Constructor using real-valued functions.
    BezierGrid(int nu, boolean uclosed, int nv, boolean vclosed)
    Constructor for an empty grid.
    BezierGrid(int nu, boolean uclosed, int nv, boolean vclosed, boolean linear)
    Constructor for an empty, possibly linear grid.
    BezierGrid(Path2D template, BezierGrid.Mapper mapper)
    Constructor given a 2D path and a Mapper.
    BezierGrid(Path2D path, Point3DMapper<Point3D> mapper, int n, boolean uclosed)
    Constructor based on a 2D path.
    BezierGrid(BezierGrid grid, boolean reverse, UnaryOperator<Point3D> f)
    Constructor based on an existing Bézier grid.
    BezierGrid(Point3D[][] points)
    Constructor.
    BezierGrid(Point3D[][] points, boolean uclosed, boolean vclosed)
    Constructor for open or closed grids.
    BezierGrid(Point3D[][] points, boolean uclosed, boolean vclosed, boolean linear)
    Constructor for open or closed grids with possibily linear connections between adjacent grid points.
  • Method Summary

    Modifier and Type
    Method
    Description
    boolean
    Test if a spline was created with inappropriate values.
    Create Bézier grids that will connect this grid to a specified grid.
    createConnectionsTo(BezierGrid grid, boolean split)
    Create Bézier grids that will connect this grid to a specified grid, optionally splitting the returned grids into multiple grids.
    createConnectionsTo(BezierGrid grid, boolean split, int... indices)
    Create Bézier grids that will connect this grid to a specified grid, optionally splitting the returned grids into multiple grids, and restricting the returned grids to ones that match a specified boundary.
    Create Bézier grids, with a specified number of vertices in the 'U' direction, that will connect this grid to a specified rid.
    createConnectionsTo(BezierGrid grid, int n, boolean split)
    Create Bézier grids that will connect this grid to a specified grid, specifying the number of vertices along a connecting grid's U axis and optionally splitting the returned grids into multiple grids.
    createConnectionsTo(BezierGrid grid, int n, boolean split, boolean exclude, int... indices)
    Create Bézier grids that will connect this grid to a specified grid, specifying the number of vertices along a connecting grid's U axis and optionally splitting the returned grids into multiple grids, and specifying pairs of indices for vertices along allowed or disallowed boundaries.
    createConnectionsTo(BezierGrid grid, int n, boolean split, int... indices)
    Create Bézier grids that will connect this grid to a specified grid, specifying the number of vertices along a connecting grid's U axis, optionally splitting the returned grids into multiple grids, and specifying pairs of indices for vertices along allowed boundaries.
    createExtensionGrid(Point3DMapper<Point3D> mapping, int[] regionChanges, int n, int uIndex, int vIndex)
    Create an extension to a Bézier grid based on a mapping function.
    void
    Create all splines.
    void
    endSpline(boolean cyclic)
    Assert that the end of a user-defined spline has been reached.
    Reverse the orientation from the current orientation.
    Get the boundary for this Shape3D.
    getBoundary(int... indices)
    Get the boundary components that pass through specific grid points.
    Get a bounding rectangular cuboid for a 3D shape.
    getComponent(int i)
    Get a component of this shape.
    boolean
    getFullSplineU(int i, int j, double[] coords)
    Get all the control points for the spline connecting a point with indices (i, j) to a point with indices (i+1, j).
    boolean
    getFullSplineV(int i, int j, double[] coords)
    Get all the control points for the spline connecting a point with indices (i, j) to a point with indices (i, j+1).
    getMapper(Path3D wire, double[] inormal)
    Get a mapper that will apply an indexed affine transform to points along a 2D or 3D curve.
    boolean
    getPatch(int i, int j, double[] coords)
    Get the coordinates for a cubic Bézier patch corresponding to the specified grid coordinates for this Bézier grid.
    getPoint(int i, int j)
    Get the current value of a point on the grid.
    boolean
    getRemainingControlPoints(int i, int j, double[] coords)
    Get the remaining control points for a patch.
    boolean
    getSplineU(int i, int j, double[] coords)
    Get the spline connecting a point with indices (i, j) to a point with indices (i+1, j).
    boolean
    getSplineV(int i, int j, double[] coords)
    Get the spline connecting a point with indices (i, j) to a point with indices (i, j+1).
    Get a surface iterator for this Shape3D.
    getSurfaceIterator(Transform3D tform, int level)
    Get a surface iterator for this Shape3D, subdividing the surface.
    int
    Get the array length in the U direction (e.g., the length for the first index).
    int
    Get the array length in the V direction (e.g., the length for the second index).
    boolean
    Determine if this Shape3D is a closed two-dimensional manifold.
    boolean
    Determine if a surface is oriented.
    boolean
    Determine if the orientation for this grid is reversed.
    boolean
    Determine if the grid is closed in the U direction.
    boolean
    Determine if the grid is closed in the V direction.
    boolean
    Determine if the grid is well formed
    boolean
    Determine if the grid is well formed, logging error messages to an Appendable
    void
    moveU(int n)
    Add elements to a spline in the U direction.
    void
    moveV(int n)
    Add elements to a spline in the V direction.
    int
    Get the number of components for this shape.
    void
    Print the points on this grid.
    void
    Print the points on this grid, using an Appendable for output.
    void
    print(String prefix)
    Print the points on this grid, specifying a prefix to be printed at the start of each line.
    void
    print(String prefix, Appendable out)
    Print the points on this grid, using an Appendable for output and specifying a prefix to be printed at the start of each line.
    void
    Print the sequence of indices for explicitly added splines.
    void
    Print the sequence of indices for explicitly added splines to an Appendable The output will list the splines in the sequence in which they were defined, and whether the splines are cyclic or not.
    void
    Print the sequence of indices for explicitly added splines to an Appendable and with a prefix The output will list the splines in the sequence in which they were defined, and whether the splines are cyclic or not.
    void
    remove(int i, int j)
    Remove a patch.
    void
    remove(int i, int j, int width, int height)
    Remove a rectangle of patches The patches removed will have indices varying from i to i+width exclusive an j to j+height exclusive.
    void
    restore(int i, int j)
    Restore a patch.
    void
    restore(int i, int j, int width, int height)
    Restore a rectangle of patches The patches restored will have indices varying from i to i+width exclusive an j to j+height exclusive.
    protected void
    Reverse the use of true and false in the method reverseOrientation(boolean).
    reverseOrientation(boolean reverse)
    Set the orientation of the patches.
    void
    setColor(int i, int j, int w, int h, Color c)
    Set the color for all patches on this grid.
    void
    setColor(int i, int j, Color c)
    Set the color for a patch on this grid.
    void
    Set the color for all patches on this grid.
    boolean
    setLinearU(int i, int j)
    Set the spline connecting a point with indices (i, j) to a point with indices (i+1, j) so that the segment is a straight line.
    boolean
    setLinearV(int i, int j)
    Set the spline connecting a point with indices (i, j) to a point with indices (i, j+1) so that the segment is a straight line.
    void
    setPatch(int i, int j, double[] coords)
    Set control points for a cubic patch associated with a grid point.
    void
    setPatchCorners(int i, int j, double[] coords)
    Set points at the corner of the cell associated with a grid location.
    void
    setPoint(int i, int j, double x, double y, double z)
    Set a point on a grid given x, y, and z coordinates for the point.
    void
    setPoint(int i, int j, Point3D p)
    Set a point on a grid.
    void
    setRegion(int i, int j, int id)
    Set a region ID.
    void
    setRegion(int i, int j, int width, int height, int id)
    Set a region ID for a rectangle of grid points.
    boolean
    setRemainingControlPoints(int i, int j, double[] rest)
    Set the remaining control points for a patch.
    boolean
    setSplineU(int i, int j, double[] coords)
    Set the spline connecting a point with indices (i, j) to a point with indices (i+1, j).
    boolean
    setSplineV(int i, int j, double[] coords)
    Set the spline connecting a point with indices (i, j) to a point with indices (i, j+1).
    void
    startSpline(int i, int j)
    Indicate the starting indices for a user-defined spline.
    subgrid(int i, int j, int n, int m)
    Create a subgrid of this Bézier grid.
    void
    Trace calls to createSpline, indicating which grid points have control points added to them.
    Transpose a BezierGrid.

    Methods inherited from class java.lang.Object

    clone, equals, finalize, getClass, hashCode, notify, notifyAll, toString, wait, wait, wait

    Methods inherited from interface org.bzdev.geom.Shape3D

    getBoundary
  • Constructor Details

    • BezierGrid

      public BezierGrid(int nu, boolean uclosed, int nv, boolean vclosed)
      Constructor for an empty grid. When a direction is closed, then when all points along a line in that direction are defined, no points along that line have been removed, and all points along that lie are in the same region, then the spline created will be a cyclic one. When closed, one should not duplicate an end point: the expected behavior occurs automatically.
      Parameters:
      nu - the number of vertices in the U direction
      uclosed - true if the U direction is close; false otherwise
      nv - the number of vertices in the V direction
      vclosed - true if the V direction is closed; false otherwise
    • BezierGrid

      public BezierGrid(int nu, boolean uclosed, int nv, boolean vclosed, boolean linear)
      Constructor for an empty, possibly linear grid. When a direction is closed, then when all points along a line in that direction are defined, no points along that line have been removed, and all points along that lie are in the same region, then the spline created will be a cyclic one. When closed, one should not duplicate an end point: the expected behavior occurs automatically.

      When the argument linear is true, each grid point is configured to have its own region. By default, each line connecting two adjacent grid points will be a straight line.

      Parameters:
      nu - the number of vertices in the U direction
      uclosed - true if the U direction is close; false otherwise
      nv - the number of vertices in the V direction
      vclosed - true if the V direction is closed; false otherwise
      linear - true if lines connecting grid points are straight lines; false otherwise
    • BezierGrid

      public BezierGrid(Point3D[][] points)
      Constructor. The points on each patch are functions of two variables u and v. Increasing u moves a point on the surface towards the next highest first index and increasing v moves a point on the surface towards the next highest second index. Both u and v must be in the range [0.0, 1.0].

      When stored, the points provided will have their coordinates rounded to the nearest 'float' value by first casting the values to a float and then to a double.

      Parameters:
      points - a two-dimensional array of points
    • BezierGrid

      public BezierGrid(Point3D[][] points, boolean uclosed, boolean vclosed)
      Constructor for open or closed grids. The points on each patch are functions of two variables u and v. Increasing u moves a point on the surface towards the next highest first index and increasing v moves a point on the surface towards the next highest second index. Both u and v must be in the range [0.0, 1.0]. If the array is an n by m array with indices [i][j], the points at i = n-1 should not repeat the points at i = 0 to create a closed surface—that will be done automatically when uclosed is true. Similarly, when vclosed is true, the points at j = m-1 should not contain the same values as those at i = 0 as the additional patches will be provided automatically.

      When uclosed or vclosed is true, the splines used to create the Bézier patches will be a smooth at all points including the end points.

      When stored, the points provided will have their coordinates rounded to the nearest 'float' value by first casting the values to a float and then to a double.

      Parameters:
      points - a two-dimensional array of points
      uclosed - the grid is closed in the U direction
      vclosed - the grid is closed in the V direction
    • BezierGrid

      public BezierGrid(Point3D[][] points, boolean uclosed, boolean vclosed, boolean linear)
      Constructor for open or closed grids with possibily linear connections between adjacent grid points. The points on each patch are functions of two variables u and v. Increasing u moves a point on the surface towards the next highest first index and increasing v moves a point on the surface towards the next highest second index. Both u and v must be in the range [0.0, 1.0]. If the array is an n by m array with indices [i][j], the points at i = n-1 should not repeat the points at i = 0 to create a closed surface—that will be done automatically when uclosed is true. Similarly, when vclosed is true, the points at j = m-1 should not contain the same values as those at i = 0 as the additional patches will be provided automatically.

      When uclosed or vclosed is true, the splines used to create the Bézier patches will be a smooth at all points including the end points.

      When stored, the points provided will have their coordinates rounded to the nearest 'float' value by first casting the values to a float and then to a double.

      When the argument linear is true, each grid point is configured to have its own region. By default, each line connecting two adjacent grid points will be a straight line.

      Parameters:
      points - a two-dimensional array of points
      uclosed - the grid is closed in the U direction
      vclosed - the grid is closed in the V direction
      linear - true if lines connecting grid points are straight lines; false otherwise
    • BezierGrid

      public BezierGrid(double[] sarray, double[] tarray, RealValuedFunctTwoOps xfunct, RealValuedFunctTwoOps yfunct, RealValuedFunctTwoOps zfunct)
      Constructor using real-valued functions. The grid is a two-dimensional array whose values are points in a three-dimensional space. The first index refers to the 'U' axis and the second index refers to the 'V' axis. The values u and v are restricted to the range [0, 1) for a given pair. of indices [i][j]. The real-valued functions are functions of two arguments (s,t). Arrays sarray and tarray are one-dimensional arrays whose indices are i and j respectively and whose values are the corresponding values for s and t.

      When stored, the points provided will have their coordinates rounded to the nearest 'float' value by first casting the values to a float and then to a double.

      Parameters:
      sarray - the 's' values at grid points in increasing order
      tarray - the 't' values at grid points in increasing order
      xfunct - the function fx(s,t) providing the X coordinate at (s,t)
      yfunct - the function fy(s,t) providing the Y coordinate at (s,t)
      zfunct - the function fz(s,t) providing the Z coordinate at (s,t)
    • BezierGrid

      public BezierGrid(double[] sarray, boolean uclosed, double[] tarray, boolean vclosed, RealValuedFunctTwoOps xfunct, RealValuedFunctTwoOps yfunct, RealValuedFunctTwoOps zfunct)
      Constructor using real-valued functions and specifying if the U and V directions are cyclic or not. The grid is a two-dimensional array whose values are points in a three-dimensional space. The first index refers to the 'U' axis and the second index refers to the 'V' axis. The values u and v are restricted to the range [0, 1) for a given pair. of indices [i][j]. The real-valued functions are functions of two arguments (s,t). Arrays sarray and tarray are one-dimensional arrays whose indices are i and j respectively and whose values are the corresponding values for s and t.

      The argument uclosed, when true, indicates that the surface corresponding to the grid is closed in the 'U' direction. Similarly vclosed, when true, indicates that the surface corresponding to the grid is closed in the 'V' direction. When the grid is closed in the U direction, sarray's final element must not repeat its initial element. Similarly when the grid is closed in the V direction, tarray's final element must not repeat its initial element.

      When stored, the coordinates provided will have their values rounded to the nearest 'float' value by first casting the values to a float and then to a double.

      Parameters:
      sarray - the 's' values at grid points in increasing order
      uclosed - true if the U direction is closed, false otherwise
      tarray - the 't' values at grid points in increasing order
      vclosed - true if the V direction is closed, false otherwise
      xfunct - the function fx(s,t) providing the X coordinate at (s,t)
      yfunct - the function fy(s,t) providing the Y coordinate at (s,t)
      zfunct - the function fz(s,t) providing the Z coordinate at (s,t)
    • BezierGrid

      public BezierGrid(double[] sarray, boolean uclosed, double[] tarray, boolean vclosed, boolean linear, RealValuedFunctTwoOps xfunct, RealValuedFunctTwoOps yfunct, RealValuedFunctTwoOps zfunct)
      Constructor using real-valued functions and specifying if the U and V directions are cyclic or not, with possibly a linear constraint for the line segments connecting adjacent points on the grid.

      The paths connecting adjectent grid points can be constrained to be linear. The grid is a two-dimensional array whose values are points in a three-dimensional space. The first index refers to the 'U' axis and the second index refers to the 'V' axis. The values u and v are restricted to the range [0, 1) for a given pair. of indices [i][j]. The real-valued functions are functions of two arguments (s,t). Arrays sarray and tarray are one-dimensional arrays whose indices are i and j respectively and whose values are the corresponding values for s and t.

      The argument uclosed, when true, indicates that the surface corresponding to the grid is closed in the 'U' direction. Similarly vclosed, when true, indicates that the surface corresponding to the grid is closed in the 'V' direction. When the grid is closed in the U direction, sarray's final element must not repeat its initial element. Similarly when the grid is closed in the V direction, tarray's final element must not repeat its initial element.

      When stored, the coordinates provided will have their values rounded to the nearest 'float' value by first casting the values to a float and then to a double.

      When the argument linear is true, each grid point is configured to have its own region. By default, each line connecting two adjacent grid points will be a straight line.

      Parameters:
      sarray - the 's' values at grid points in increasing order
      uclosed - true if the U direction is closed, false otherwise
      tarray - the 't' values at grid points in increasing order
      vclosed - true if the V direction is closed, false otherwise
      linear - true if lines connecting grid points are straight lines; false otherwise
      xfunct - the function fx(s,t) providing the X coordinate at (s,t)
      yfunct - the function fy(s,t) providing the Y coordinate at (s,t)
      zfunct - the function fz(s,t) providing the Z coordinate at (s,t)
    • BezierGrid

      public BezierGrid(BezierGrid grid, boolean reverse, UnaryOperator<Point3D> f)
      Constructor based on an existing Bézier grid. Modifications to the existing grid by calls to setSplineU(int,int,double[]), setSplineV(int,int,double[]), or setRemainingControlPoints(int,int,double[]) will not be copied to the new grid. Other modifications (additional splines and the removal of grid cells) will be copied. The unary operator argument f, if not null, will map a point on the existing grid to the corresponding point on the new grid. If f is null, the two grids will share identical grid points.

      If, for example, a BezierGrid grid1 represents a 'top' half of a sphere centered on (0,0,0), with the boundary of grid1 having Z values of zero,

      
          BezierGrid grid2 = new BezierGrid(grid1, true, (p) -> {
               double z = p.getZ();
               if (z > 0) z = -z;
               return new Point2D.Double(p.getX(), p.getY(), z);
             });
          ...
          Surface3D surface = new Surface3D.Double();
          surface.append(grid1);
          surface.append(grid2);
       
      will create the 'bottom' half of the sphere. If the configuration for grid 1 is changed (e.g., by adding splines to represent paths with a constant 'latitude'), the corresponding changes will not have to be made to grid 2.

      While the grid points, regions, splines, and whether or not a patch associated with a grid point has been removed are copied to the new grid, explicitly-set control points are not copied. As a result, if the argument grid is a subgrid, or if the argument grid's methods setSplineU(int,int,double[]), setSplineV(int,int,double[]), or setRemainingControlPoints(int,int,double[]) have been called, one may have to use these methods on the newly created grid to get the desired results. For example, consider the following statements:

      
         BezierGrid grid1 = new BezierGrid(array);
         BezierGrid grid2 = grid1.subgrid(10,10,6,2);
         BezierGrid grid3 = new BezierGrid(grid2, false, (p) -> {
               return p;
             });
       
      One might expect grid2 and grid 3 to be identical. They may not be identical because the splines for grid2 are those computed for grid1, but grid1 and grid3, except for some special cases, compute their splines using different end points.
      Parameters:
      grid - the existing grid
      reverse - true if this grid should have the opposite orientation from the existing grid; false if this grid should have the same orientation
      f - a unary operator to map an existing grid point into a new one.
    • BezierGrid

      public BezierGrid(Path2D path, Point3DMapper<Point3D> mapper, int n, boolean uclosed)
      Constructor based on a 2D path. A default method of the interface Point3DMapper first converts the control points into a Point3D with the same X and Y values, and a Z value of 0.0, and then calls the method Point3DMapper.apply(int,Point3D,Point3DMapper.Type,Point3D...) on each control point to set the Bézier curves in the V direction, repeated with the index indicating the position along the U direction. The resulting grid will generate splines along the U direction but will not alter the splines in the V direction.

      If mapper makes the 2D path's Y coordinate the Z coordinate and treats the 2D path's X coordinate (or a non-negative function of that coordinate) as a radius, if the 2D path's shape is such that traversing this path (when closed) is counterclockwise, and if increasing the mapper's index results in a counterclockwise rotation about the Z axis, then the surface's orientation will be correct. Othewise the surface willhave to be flipped.

      Parameters:
      path - the path
      mapper - the object that maps 2D points to 3D points
      n - the number of points along the U axis.
      uclosed - true if the U direction is closed, false otherwise
    • BezierGrid

      public BezierGrid(Path2D template, BezierGrid.Mapper mapper)
      Constructor given a 2D path and a Mapper. The mapper can be created by getMapper(Path3D,double[]) and that mapper will be used to create the points along the grid. Control points for two-dimensional path template will be mapped and set for control points along the V axis. The number of points long the U axis is given by BezierGrid.Mapper.getN() and whether or not the U direction is closed is determined by BezierGrid.Mapper.isClosed().

      This constructor can be used to create 'wires' with the template specifying the cross section, with getMapper(Path3D,double[]) creating a mapper given the wire's path. When getMapper(Path3D,double[]) is used, the point (0,0) will be mapped to a point on the 3D path provided by getMapper, a unit vector pointing along X axis in the 2 dimensional space containing the template will be mapped to the unit normal vector N for a point on the wire's path. Similarly a unit vector pointing along the Y axis in the 2 dimensional space containing the template will be mapped to the unit vector N × T, where T is the unit tangent vector for the same point on the wire's path.

      Parameters:
      template - a two-dimensional path representing a cross section of a 'wire'
      mapper - an instance of BezierGrid.Mapper that maps points on the template to points on the 'wire'
  • Method Details

    • getUArrayLength

      public int getUArrayLength()
      Get the array length in the U direction (e.g., the length for the first index).
      Returns:
      the array length for the U direction
    • getVArrayLength

      public int getVArrayLength()
      Get the array length in the V direction (e.g., the length for the second index).
      Returns:
      the array length for the V direction
    • isUClosed

      public boolean isUClosed()
      Determine if the grid is closed in the U direction.
      Returns:
      true if the grid is closed in the U direction; false otherwise
    • isVClosed

      public boolean isVClosed()
      Determine if the grid is closed in the V direction.
      Returns:
      true if the grid is closed in the V direction; false otherwise
    • reverseFlip

      protected void reverseFlip()
      Reverse the use of true and false in the method reverseOrientation(boolean).
    • getMapper

      public static BezierGrid.Mapper getMapper(Path3D wire, double[] inormal)
      Get a mapper that will apply an indexed affine transform to points along a 2D or 3D curve. The indexes range from 0 to N where N is the value returned by Path3DInfo.numberOfDrawableSegments(wire). This mapper treats a two dimensional point (x, y) the same as the three dimenional point (x, y, 0.0).

      For each segment along the path 'wire' that starts with a unit tangent vector T, a unit vector N perpendicular to T is set to a unit vector in the direction T × (N′ × T), where N′ is the previous value of N. The initial value of N′ is the vector given by the argument inormal. For points along a 2 dimensional path, an affine transform maps a unit vector in the X direction to N, a unit vector in the Y direction to (N × T), and the point (0,0) to the ith point along the 3D path wire, excluding intermediate control points.

      Straight-line segments along the 'wire' path are handled specially: these are given a region that distinguishes these segments from those that precede them or follow them so that straight line segments in the 'wire' path correspond to cylindrical sections along the generated surface.

      The normal vector is represented by an array containing the vector's X, Y and Z coordinates in that order, and its norm does not matter as long as it is not zero. The class VectorOps contains methods that can simplify the creation of normal vectors, specifically VectorOps.createUnitVector3(double,double), which uses spherical coordinates.

      Parameters:
      wire - a 3D path, either open or closed
      inormal - the vector that provides an initial normal vector (ignored if a normal vector can be computed from the 'wire')
      Returns:
      the mapper
      See Also:
    • transpose

      public BezierGrid transpose()
      Transpose a BezierGrid. This method returns a new grid with the U and V coordinates swapped. The transposed grid will be in the same state as the original. Because of the way orientations are determined, a transposed grid's orientation is opposite to that of the original grid.
      Returns:
      the transposed grid
      Throws:
      IllegalStateException - the grid to be transposed was created as an extension to an existing grid or as a connection between existing grid boundaries; a user-defined spline was started but not finished
    • subgrid

      public BezierGrid subgrid(int i, int j, int n, int m)
      Create a subgrid of this Bézier grid. A subgrid is never a closed grid in either the U or V directions, or both. The maximum size of a subgrid in either the U or V directions is the corresponding size of this grid. When this grid is not closed in the U direction and the size of this grid in the U direction is nu, then n ≤ nu-i. Similarly when this grid is not closed in the U direction and the size of this grid in the V direction is nv, then m ≤ nv-i. The indices (i, j) must satisfy i ∈ [0,nu) and j ∈ [0, nv). A subgrid will copy this grid's splines and will be 'frozen' (i.e., the subgrid's splines cannot be modified).

      While a subgrid can be used to isolate a portion of a grid for convenience, it's main purpose is to handle cases where the full grid is not well formed. For example, to create a Möbius strip that can be 3D printed, one can start with a template representing a rectangle, and apply an affine transformation to create copies at points along the strip:

      
         int N = 64;
         int M = 4;
      
        Point3D[][] array = new Point3D[2*N][M];
        Point3D[] template = new Point3D[M];
      
        double r = 100.0;
        double width = 50.0;
        double height = 10.0;
      
        template[0] = new Point3D.Double(0.0, width/2, height/2);
        template[1] = new Point3D.Double(0.0, -width/2,height/2);
        template[2] = new Point3D.Double(0.0, -width/2,-height/2);
        template[3] = new Point3D.Double(0.0, width/2, -height/2);
      
        for (int i = 0; i < 2*N; i++) {
            double theta = (Math.PI * i)/N;
            double psi = (2 * Math.PI * i)/N;
            AffineTransform3D af =
            AffineTransform3D.getRotateInstance(0.0, 0.0, psi);
            af.translate(0.0, r, 0.0);
            af.rotate(0.0, theta, 0.0);
            for (int j = 0; j < M; j++) {
                array[i][j] = af.transform(template[j], null);
            }
        }
        BezierGrid grid = new BezierGrid(array, true, true);
        for (int i = 0; i < 2*N; i++) {
            for (int j = 0; j < M; j++) {
                grid.setRegion(i, j, j);
            }
        }
        BezierGrid mgrid = grid.subgrid(0, 0, N+1, M+1);
       
      The U values for a full grid cover an angular extent of of 4π so that corresponding points match at the ends and so that the splines in the U direction are cyclic. Because the V values follow a rectangle, the region for each point is set to the value of its V index, which forces all the edges in the V direction to be linear. Unfortunately, the full grid has multiple vertices that correspond to the same points, so this grid is not well formed. The use of a subgrid extracts a grid corresponding to an angular extent of 2π, which is just enough for the desired Möbius strip.
      Parameters:
      i - the U index for an index of this grid that will correspond to the index (0,0) for the subgrid
      j - the V index for an index of this grid that will correspond to the index (0,0) for the subgrid
      n - the number of grid points in the U direction for the subgrid
      m - the number of grid points in the V direction for the subgrid
      Returns:
      the subgrid
    • getFullSplineU

      public boolean getFullSplineU(int i, int j, double[] coords)
      Get all the control points for the spline connecting a point with indices (i, j) to a point with indices (i+1, j). The coords array will contain the initial, first, second, and final control points in that order. For each control point, the array contains three successive values giving the control point's X, Y, and Z coordinates respectively.

      Intermediate control points will be set along all grid segments as a side effect of calling this method.

      Parameters:
      i - the U index
      j - the V index
      coords - and array to hold the results
      Returns:
      true if the spline exists; false if it does not
    • getFullSplineV

      public boolean getFullSplineV(int i, int j, double[] coords)
      Get all the control points for the spline connecting a point with indices (i, j) to a point with indices (i, j+1). The coords array will contain the initial, first, second, and final control points in that order. For each control point, the array contains three successive values giving the control point's X, Y, and Z coordinates respectively.

      Intermediate control points will be set along all grid segments as a side effect of calling this method.

      Parameters:
      i - the U index
      j - the V index
      coords - an array to hold the results
      Returns:
      true if the spline exists; false if it does not
    • getSplineU

      public boolean getSplineU(int i, int j, double[] coords)
      Get the spline connecting a point with indices (i, j) to a point with indices (i+1, j). The coords array will contain the first, second, and final control points in that order, but not the initial control point. For each control point, the array contains three successive values giving the control point's X, Y, and Z coordinates respectively.

      Intermediate control points will be set along all grid segments as a side effect of calling this method.

      Parameters:
      i - the U index
      j - the V index
      coords - and array to hold the results
      Returns:
      true if the spline exists; false if it does not
    • getSplineV

      public boolean getSplineV(int i, int j, double[] coords)
      Get the spline connecting a point with indices (i, j) to a point with indices (i, j+1). The coords array will contain the first, second, and final control points in that order, but not the initial control point. For each control point, the array contains three successive values giving the control point's X, Y, and Z coordinates respectively.

      Intermediate control points will be set along all grid segments as a side effect of calling this method.

      Parameters:
      i - the U index
      j - the V index
      coords - and array to hold the results
      Returns:
      true if the spline exists; false if it does not
    • setSplineU

      public boolean setSplineU(int i, int j, double[] coords)
      Set the spline connecting a point with indices (i, j) to a point with indices (i+1, j). The array must have a length of at least 6, and will contain the first and second control points, but not the initial or final control points (if the final point is present in the array, that value is ignored). For each control point, the array contains three successive values giving the control point's X, Y, and Z coordinates respectively.

      After this method is called, and successfully returns, splines cannot be defined by sequences of methods starting with calls to startSpline(int,int) and grid points cannot be modified (e.g, by calling setPoint(int,int,Point3D).

      When stored, the coordinates provided will have their values rounded to the nearest 'float' value by first casting the values to a float and then to a double.

      This method returns false if the grid is a linear grid: one created with the constructors BezierGrid(int,boolean,int,boolean,boolean), BezierGrid(Point3D[][],boolean,boolean,boolean), or BezierGrid(double[],boolean,double[],boolean,boolean,RealValuedFunctTwoOps,RealValuedFunctTwoOps,RealValuedFunctTwoOps), with its 'linear' argument set to true.

      Parameters:
      i - the U index
      j - the V index
      coords - the coordinates for the intermediate control points.
      Returns:
      true if the spline is allowed for this point; false if it is not
      Throws:
      IllegalArgumentException - the coords array is too short or i and/or j are out of range
    • setLinearU

      public boolean setLinearU(int i, int j)
      Set the spline connecting a point with indices (i, j) to a point with indices (i+1, j) so that the segment is a straight line. After this method is called, and successfully returns, splines cannot be defined by sequences of methods starting with calls to startSpline(int,int) and grid points cannot be modified (e.g, by calling setPoint(int,int,Point3D).

      When stored, the coordinates provided will have their values rounded to the nearest 'float' value by first casting the values to a float and then to a double.

      This method merely calls setSplineU(int,int,double[]) with the appropriate argument, and should be used when a linear segment will be attached to a planar triangle in order to ensure that the tessellation will work as expected: otherwise small floating-point errors can result in a surface that is not well formed.

      This method returns false if the grid is a linear grid: one created with the constructors BezierGrid(int,boolean,int,boolean,boolean), BezierGrid(Point3D[][],boolean,boolean,boolean), or BezierGrid(double[],boolean,double[],boolean,boolean,RealValuedFunctTwoOps,RealValuedFunctTwoOps,RealValuedFunctTwoOps), with its 'linear' argument set to false.

      Parameters:
      i - the U index
      j - the V index
      Returns:
      true if the spline is allowed for this point; false if it is not
      Throws:
      IllegalArgumentException - i and/or j are out of range
    • setLinearV

      public boolean setLinearV(int i, int j)
      Set the spline connecting a point with indices (i, j) to a point with indices (i, j+1) so that the segment is a straight line. After this method is called, and successfully returns, splines cannot be defined by sequences of methods starting with calls to startSpline(int,int) and grid points cannot be modified (e.g, by calling setPoint(int,int,Point3D).

      When stored, the coordinates provided will have their values rounded to the nearest 'float' value by first casting the values to a float and then to a double.

      This method merely calls setSplineV(int,int,double[]) with the appropriate argument, and should be used when a linear segment will be attached to a planar triangle in order to ensure that the tessellation will work as expected: otherwise small floating-point errors can result in a surface that is not well formed.

      This method returns false if the grid is a linear grid: one created with the constructors BezierGrid(int,boolean,int,boolean,boolean), BezierGrid(Point3D[][],boolean,boolean,boolean), or BezierGrid(double[],boolean,double[],boolean,boolean,RealValuedFunctTwoOps,RealValuedFunctTwoOps,RealValuedFunctTwoOps), with its 'linear' argument set to true.

      Parameters:
      i - the U index
      j - the V index
      Returns:
      true if the spline is allowed for this point; false if it is not
      Throws:
      IllegalArgumentException - i and/or j are out of range
    • setSplineV

      public boolean setSplineV(int i, int j, double[] coords)
      Set the spline connecting a point with indices (i, j) to a point with indices (i, j+1). The array must have a length of at least 6, and will contain the first and second control points, but not the initial or final control points (if the final point is present in the array, that value is ignored). For each control point, the array contains three successive values giving the control point's X, Y, and Z coordinates respectively.

      After this method is called, and successfully returns, splines cannot be defined by sequences of methods starting with calls to startSpline(int,int) and grid points cannot be modified (e.g, by calling setPoint(int,int,Point3D).

      When stored, the coordinates provided will have their values rounded to the nearest 'float' value by first casting the values to a float and then to a double.

      This method returns false if the grid is a linear grid: one created with the constructors BezierGrid(int,boolean,int,boolean,boolean), BezierGrid(Point3D[][],boolean,boolean,boolean), or BezierGrid(double[],boolean,double[],boolean,boolean,RealValuedFunctTwoOps,RealValuedFunctTwoOps,RealValuedFunctTwoOps). with its 'linear' argument set to true.

      Parameters:
      i - the U index
      j - the V index
      coords - and array to hold the results
      Returns:
      true if the spline is allowed for this point; false if it is not
      Throws:
      IllegalArgumentException - the coords array is too short or i and/or j are out of range
    • setRemainingControlPoints

      public boolean setRemainingControlPoints(int i, int j, double[] rest) throws IllegalArgumentException
      Set the remaining control points for a patch. The control points P11, P12, P21 and P22 are specified by an array (rest) of length 12, each stored so that the X value of a control point is followed by its Y value and in turn by its Z value, with the control points listed in the order shown.

      If this method is not called for a pair of indices or the control-point array is null, a default will be used to generate the missing control points.

      When stored, the coordinates provided will have their values rounded to the nearest 'float' value by first casting the values to a float and then to a double.

      This method returns false if the grid is a linear grid: one created with the constructors BezierGrid(int,boolean,int,boolean,boolean), BezierGrid(Point3D[][],boolean,boolean,boolean), or BezierGrid(double[],boolean,double[],boolean,boolean,RealValuedFunctTwoOps,RealValuedFunctTwoOps,RealValuedFunctTwoOps). with its 'linear' argument set to true.

      Parameters:
      i - the U index, which must be in the range [0,N) where N is the largest allowable U index
      j - the V index, which must be in the range[0,M) where M is the largest allowable V index
      rest - an array holding the remaining control points; null if these should be cleared
      Returns:
      true if a patch exists for this point; false if it does not
      Throws:
      IllegalArgumentException - an argument was out of range or the array was too small
    • getRemainingControlPoints

      public boolean getRemainingControlPoints(int i, int j, double[] coords) throws IllegalArgumentException
      Get the remaining control points for a patch. The control points P11, P12, P21 and P22 are specified by an array (rest) of length 12, each stored so that the X value of a control point is followed by its Y value and in turn by its Z value, with the control points listed in the order shown.
      Parameters:
      i - the U index, which must be in the range [0,N) where N is the largest allowable U index
      j - the V index, which must be in the range[0,M) where M is the largest allowable V index
      coords - an array that will hold the remaining control points
      Returns:
      true if a patch exists for this point with explicit values for the remaining control points; otherwise false
      Throws:
      IllegalArgumentException - if an argument was out of range or the array was too small
    • getPoint

      public Point3D getPoint(int i, int j)
      Get the current value of a point on the grid.
      Parameters:
      i - the U index
      j - the V index
      Returns:
      the corresponding point; null if there is none
    • getPatch

      public boolean getPatch(int i, int j, double[] coords)
      Get the coordinates for a cubic Bézier patch corresponding to the specified grid coordinates for this Bézier grid. The patch can be added directly to a surface: if this grid has its orientation reversed, that will not be reflected in the patch coordinates.
      Parameters:
      i - the U index, which must be in the range [0,N) where N is the largest allowable U index
      j - the V index, which must be in the range[0,M) where M is the largest allowable V index
      coords - an array of length 48 or larger that will hold the coordinates for a patch
      Returns:
      true if patch coordinates can be computed; otherwise false
      Throws:
      IllegalArgumentException - the arguments are out of range or the coordinates array is too small
    • setPoint

      public void setPoint(int i, int j, Point3D p) throws IllegalArgumentException, IllegalStateException
      Set a point on a grid. This method can be used to adjust the value of points on the grid. It must be called before any call to the methods setSplineU(int,int,double[]), setSplineV(int,int,double[]), or setRemainingControlPoints(int,int,double[]). If a grid point already exists, its cell's status (empty or filled) is unchanged. Otherwise its cell status is set to filled if the point is non null and empty if the point is null
      Parameters:
      i - the U index
      j - the V index
      p - the point
      Throws:
      IllegalArgumentException - an index was out of range
      IllegalStateException - splines were previously set by calls to setSplineU(int,int,double[]), setSplineV(int,int,double[]), or setRemainingControlPoints(int,int,double[])
      See Also:
    • setPatchCorners

      public void setPatchCorners(int i, int j, double[] coords) throws IllegalArgumentException, IllegalStateException
      Set points at the corner of the cell associated with a grid location. For each corner, if a grid point already exists, its cell's status (empty or filled) is unchanged. Otherwise its cell status is set to filled.
      Parameters:
      i - the U index
      j - the V index
      coords - the control points.
      Throws:
      IllegalArgumentException
      IllegalStateException
      See Also:
    • setPatch

      public void setPatch(int i, int j, double[] coords) throws IllegalArgumentException, IllegalStateException
      Set control points for a cubic patch associated with a grid point. For each corner, if a grid point already exists, its cell's status (empty or filled) is unchanged. Otherwise its cell status is set to filled.

      This throws an exception if the grid is a linear grid: one created with the constructors BezierGrid(int,boolean,int,boolean,boolean), BezierGrid(Point3D[][],boolean,boolean,boolean), or BezierGrid(double[],boolean,double[],boolean,boolean,RealValuedFunctTwoOps,RealValuedFunctTwoOps,RealValuedFunctTwoOps), with its 'linear' argument set to true.

      Parameters:
      i - the U index of the grid point
      j - the V index of the grid point
      coords - the control points.
      Throws:
      IllegalArgumentException - if an argument is out of range
      IllegalStateException - if a patch may not be set
      See Also:
    • setPoint

      public void setPoint(int i, int j, double x, double y, double z) throws IllegalArgumentException, IllegalStateException
      Set a point on a grid given x, y, and z coordinates for the point. This method can be used to adjust the value of points on the grid. It must be called before any call to the methods setSplineU(int,int,double[]), setSplineV(int,int,double[]), or setRemainingControlPoints(int,int,double[]).

      When stored, the coordinates provided will have their values rounded to the nearest 'float' value by first casting the values to a float and then to a double. If a grid point already exists, its cell's status (empty or filled) is unchanged. Otherwise its cell status is set to filled.

      Parameters:
      i - the U index
      j - the V index
      x - the point's X coordinate
      y - the point's Y coordinate
      z - the point's Z coordinate
      Throws:
      IllegalArgumentException - the coords array is too short or i and j are out of range
      IllegalStateException - splines were previously set by calls to setSplineU(int,int,double[]), setSplineV(int,int,double[]), or setRemainingControlPoints(int,int,double[])
    • startSpline

      public void startSpline(int i, int j) throws IllegalArgumentException
      Indicate the starting indices for a user-defined spline. The indices i and j vary in the U and V directions respectively. For example for fixed j, the value when u = 1.0 and v = 0.0 at grid element (i, j) is the same as the value when = u 0.0 and v = 0.0 at grid element(i+1, j).
      Parameters:
      i - the first index
      j - the second index
      Throws:
      IllegalArgumentException - the coords array is too short or i and j are out of range
      See Also:
    • moveV

      public void moveV(int n)
      Add elements to a spline in the V direction. The current index will change from (i, j) to (i, j+n). The method does nothing if the argument is 0.
      Parameters:
      n - a positive number when n elements are added to the spline in the positive V direction; a negative number when -n elements are added to the spline in the negative V direction
      Throws:
      IllegalArgumentException - the argument was out of range
      IllegalStateException - a spline has not been stated
      See Also:
    • moveU

      public void moveU(int n)
      Add elements to a spline in the U direction. The current index will change from (i, j) to (i+n, j). The method does nothing if the argument is 0.
      Parameters:
      n - a positive number when n elements are added to the spline in the positive U direction; a negative number when -n elements are added to the spline in the negative U direction
      Throws:
      IllegalArgumentException - the argument was out of range
      IllegalStateException - a spline has not been stated
      See Also:
    • endSpline

      public void endSpline(boolean cyclic) throws IllegalStateException
      Assert that the end of a user-defined spline has been reached. For a non-cyclic spline, the current point for the spline is the end point of the spline. For a cyclic spline, points will be added in either the U or V direction, but not both, until the spline is completed
      Parameters:
      cyclic - true if the spline is cyclic, false otherwise
      Throws:
      IllegalStateException - if the spline is cyclic and cannot be completed by moving in the U direction or the V direction but not both, or if a spline has not been started
      See Also:
    • print

      public void print()
      Print the points on this grid. The output will first indicate if the grid is closed in the U and V directions. This will be followed by the string "grid:" followed by a series of lines showing each point as an ordered triplet of X, Y, and Z coordinates, or the string "(null)" if undefined. Each line corresponds to a successively higher U coordinate, with points on each line in ascending order for their V coordinates. This is followed by a line containing the string "spline status", followed by lines containing the strings
      • (uv) if a grid point has both U and V intermediate control points defined.
      • (u ) if a grid point has only U intermediate control points defined.
      • ( v) if a grid point has only V intermediate control points defined.
      • (  ) if a grid point has no intermediate control points defined
      This information uses the same ordering as the grid coordinates. These lines are followed by a line containing the string "filled status:", in turn followed by a series of lines containing
      • (F) if a grid point's cell is filled (i.e., part of a surface.)
      • ( ) if a grid point's cell is not filled (in which case it is part of a boundary.)
      As with the other lines, these are ordered so that successive lines are in ascending order for U values and each line is in ascending order for V values.
      Throws:
      RuntimeException - an IO error occurred
    • print

      public void print(Appendable out)
      Print the points on this grid, using an Appendable for output.

      This method calls createSplines() if it has not already been called, but the state is restored so that createSplines() can be called subsequently. There is, however, a side effect: the intermediate control points for each spline will be set.

      The output will first indicate if the grid is closed in the U and V directions. This will be followed by the string "grid:" followed by a series of lines showing each point as an ordered triplet of X, Y, and Z coordinates, or the string "(null)" if undefined. Each line corresponds to a successively higher U coordinate, with points on each line in ascending order for their V coordinates. This is followed by a line containing the string "spline status", followed by lines containing the strings

      • (uv) if a grid point has both U and V intermediate control points defined.
      • (u ) if a grid point has only U intermediate control points defined.
      • ( v) if a grid point has only V intermediate control points defined.
      • (  ) if a grid point has no intermediate control points defined
      This information uses the same ordering as the grid coordinates. These lines are followed by a line containing the string "filled status:", in turn followed by a series of lines containing
      • (F) if a grid point's cell is filled (i.e., part of a surface.)
      • ( ) if a grid point's cell is not filled (in which case it is part of a boundary.)
      As with the other lines, these are ordered so that successive lines are in ascending order for U values and each line is in ascending order for V values.
      Parameters:
      out - the output
      Throws:
      RuntimeException - an IO error occurred
    • print

      public void print(String prefix)
      Print the points on this grid, specifying a prefix to be printed at the start of each line.

      This method calls createSplines() if it has not already been called, but the state is restored so that createSplines() can be called subsequently. There is, however, a side effect: the intermediate control points for each spline will be set. The output will first indicate if the grid is closed in the U and V directions. This will be followed by the string "grid:" followed by a series of lines showing each point as an ordered triplet of X, Y, and Z coordinates, or the string "(null)" if undefined. Each line corresponds to a successively higher U coordinate, with points on each line in ascending order for their V coordinates. This is followed by a line containing the string "spline status", followed by lines containing the strings

      • (uv) if a grid point has both U and V intermediate control points defined.
      • (u ) if a grid point has only U intermediate control points defined.
      • ( v) if a grid point has only V intermediate control points defined.
      • (  ) if a grid point has no intermediate control points defined
      This information uses the same ordering as the grid coordinates. These lines are followed by a line containing the string "filled status:", in turn followed by a series of lines containing
      • (F) if a grid point's cell is filled (i.e., part of a surface.)
      • ( ) if a grid point's cell is not filled (in which case it is part of a boundary.)
      As with the other lines, these are ordered so that successive lines are in ascending order for U values and each line is in ascending order for V values.
      Parameters:
      prefix - the prefix
      Throws:
      RuntimeException - an IO error occurred
    • print

      public void print(String prefix, Appendable out)
      Print the points on this grid, using an Appendable for output and specifying a prefix to be printed at the start of each line.

      This method calls createSplines() if it has not already been called, but the state is restored so that createSplines() can be called subsequently. There is, however, a side effect: the intermediate control points for each spline will be set.

      The output will first indicate if the grid is closed in the U and V directions. This will be followed by the string "grid:" followed by a series of lines showing each point as an ordered triplet of X, Y, and Z coordinates, or the string "(null)" if undefined. Each line corresponds to a successively higher U coordinate, with points on each line in ascending order for their V coordinates. This is followed by a line containing the string "spline status", followed by lines containing the strings

      • (uv) if a grid point has both U and V intermediate control points defined.
      • (u ) if a grid point has only U intermediate control points defined.
      • ( v) if a grid point has only V intermediate control points defined.
      • (  ) if a grid point has no intermediate control points defined
      This information uses the same ordering as the grid coordinates. These lines are followed by a line containing the string "filled status:", in turn followed by a series of lines containing
      • (F) if a grid point's cell is filled (i.e., part of a surface.)
      • ( ) if a grid point's cell is not filled (in which case it is part of a boundary.)
      As with the other lines, these are ordered so that successive lines are in ascending order for U values and each line is in ascending order for V values.
      Parameters:
      prefix - the prefix
      out - the output
      Throws:
      RuntimeException - an IO error occurred
    • printSplines

      public void printSplines()
      Print the sequence of indices for explicitly added splines. The output will list the splines in the sequence in which they were defined, and whether the splines are cyclic or not. Sequences of index pairs in which more than one have an index in common are separated by " ... "; otherwise by ", ".
      Throws:
      RuntimeException - an IO error occurred
    • printSplines

      public void printSplines(Appendable out)
      Print the sequence of indices for explicitly added splines to an Appendable The output will list the splines in the sequence in which they were defined, and whether the splines are cyclic or not. Sequences of index pairs in which more than one have an index in common are separated by " ... "; otherwise by ", ".
      Parameters:
      out - the Appendable used for output.
      Throws:
      RuntimeException - an IO error occurred
    • printSplines

      public void printSplines(String prefix, Appendable out)
      Print the sequence of indices for explicitly added splines to an Appendable and with a prefix The output will list the splines in the sequence in which they were defined, and whether the splines are cyclic or not. Sequences of index pairs in which more than one have an index in common are separated by " ... "; otherwise by ", ". The prefix will typically be used in cases where extra indentation is useful.
      Parameters:
      prefix - a prefix to place at the start of each line
      out - the Appendable used for output.
      Throws:
      RuntimeException - an IO error occurred
    • badSplines

      public boolean badSplines(Appendable out)
      Test if a spline was created with inappropriate values. This method is intended for debugging. Note: if the X, Y, or Z coordinate of a point on the grid has the value Double.NaN, this method may report an error. One can check the values at adjacent points on the grid to help detect this condition.

      This method calls createSplines() if it has not already been called, but the state is restored so that createSplines() can be called subsequently. There is, however, a side effect: the intermediate control points for each spline will be set.

      Parameters:
      out - the output to use for printing messages
      Returns:
      true if a spline was created with inconsistent values; false if the splines are acceptable
      Throws:
      RuntimeException - an IO error occurred
    • traceSplines

      public void traceSplines(Appendable out)
      Trace calls to createSpline, indicating which grid points have control points added to them. This method is useful primarily for debugging. If IO errors occur, the output will be silently dropped.
      Parameters:
      out - an Appendable that will store the trace.
    • createSplines

      public void createSplines() throws IllegalStateException
      Create all splines. A standard set of splines will be created first, followed by user-defined splines. If called more than once, the additional calls are ignored unless a vertex is changed or a new spline is added.

      When stored, the coordinates of control points will have their values rounded to the nearest float value by first casting a value as a float and then casting the result back to a double.

      Throws:
      IllegalStateException - a spline could not be created or was ill formed
    • reverseOrientation

      public BezierGrid reverseOrientation(boolean reverse)
      Set the orientation of the patches. This method affects the orientation of patches provided by iterators. It does not change the values returned by calling methods such as getFullSplineU(int,int,double[]), getFullSplineV(int,int,double[]), getSplineU(int,int,double[]), or getSplineV(int,int,double[]).
      Parameters:
      reverse - true if the orientation is the reverse of the one that was initially defined; false if the orientation is the same as the one that was initially defined.
      Returns:
      this grid
    • flip

      public BezierGrid flip()
      Reverse the orientation from the current orientation. This method affects the orientation of patches provided by iterators. It does not change the values returned by calling methods such as getFullSplineU(int,int,double[]), getFullSplineV(int,int,double[]), getSplineU(int,int,double[]), or getSplineV(int,int,double[]).

      When using the method {#transpose()}, the new grid's initial orientation is opposite to the current grid's initial orientation, but if the current grid is reversed, the new grid will be reversed as well. To force the new grid to have the same orientation as the current grid, flip() can be used.

      Returns:
      this grid
    • isReversed

      public boolean isReversed()
      Determine if the orientation for this grid is reversed.
      Returns:
      true if the orientation is reversed; false if not
    • setRegion

      public void setRegion(int i, int j, int id)
      Set a region ID. Regions represent collections of points whose boundaries terminate the implicitly generated splines so that the curves at the border of a region may not have continuous derivatives. A region is represented by an integer ID. Implicitly generated splines have constant indices in either the U or V directions, but not both. As the varying index increases, a spline terminates either when the maximum index is reached or at the first index for which the region ID changes. That index is also the one for the start of the next spline. All grid points are initialized to be in Region 0. This method must be used to change a point's region ID from this default.
      Parameters:
      i - the index for the U direction
      j - the index for the V direction
      id - the region id
      Throws:
      IllegalArgumentException - the arguments are out of range
    • setRegion

      public void setRegion(int i, int j, int width, int height, int id)
      Set a region ID for a rectangle of grid points. Regions represent collections of points whose boundaries terminate the implicitly generated splines so that the curves at these locations may not have continuous derivatives. A region is represented by an integer ID. A region is represented by an integer ID. Implicitly generated splines have constant indices in either the U or V directions, but not both. As the varying index increases, a spline terminates either when the maximum index is reached or at the first index for which the region ID changes. That index is also the one for the start of the next spline. All grid points are initialized to be in Region 0. This method must be used to change a point's region ID from this default.
      Parameters:
      i - the index for the start of the rectangle in the U direction
      j - the index for the start of the rectangle in the V direction
      width - the number of indices in the U direction
      height - the number of indices in the V diction
      id - the region id
      Throws:
      IllegalArgumentException - if an argument was out of range
      IllegalStateException - if called on a linear BezierGrid
    • remove

      public void remove(int i, int j)
      Remove a patch. The indices (i, j) specify the point at u=0, v=0 for the corresponding patch. When a patch is removed, the patch is not used as part of a 3D shape, but its point (u=0, v=0) is used in creating splines.
      Parameters:
      i - the index for the U direction
      j - the index for the V direction
    • remove

      public void remove(int i, int j, int width, int height)
      Remove a rectangle of patches The patches removed will have indices varying from i to i+width exclusive an j to j+height exclusive. both the width and the height must be non-negative. When a patch is removed, the patch is not used as part of a 3D shape, but its point (u=0, v=0) is used in creating splines.
      Parameters:
      i - the index for the start of the rectangle in the U direction
      j - the index for the start of the rectangle in the V direction
      width - the number of indices in the U direction
      height - the number of indices in the V diction
    • restore

      public void restore(int i, int j)
      Restore a patch. The indices (i, j) specify the point at u=0, v=0 for the corresponding patch. This reverses the effect of calling remove(int,int).
      Parameters:
      i - the index in the U direction
      j - the index in the V direction
    • restore

      public void restore(int i, int j, int width, int height)
      Restore a rectangle of patches The patches restored will have indices varying from i to i+width exclusive an j to j+height exclusive. both the width and the height must be non-negative. This reverses the effect of calling remove(int,int,int,int).
      Parameters:
      i - the index for the start of the rectangle in the U direction
      j - the index for the start of the rectangle in the V direction
      width - the number of indices in the U direction
      height - the number of indices in the V diction
    • getSurfaceIterator

      public SurfaceIterator getSurfaceIterator(Transform3D tform)
      Description copied from interface: Shape3D
      Get a surface iterator for this Shape3D. The surface iterator will represent the shape as a sequence of Bézier patches and Bézier triangles, with the order of the sequence arbitrary.

      Unless the transform is an affine transform, the transformation is not exact. In this case, the patches and triangles that constitute the surface should be small enough that the transform can be approximated by an affine transform over the region containing the control points.

      Specified by:
      getSurfaceIterator in interface Shape3D
      Parameters:
      tform - a transform to apply to each control point; null for the identity transform
      Returns:
      a surface iterator
    • getSurfaceIterator

      public final SurfaceIterator getSurfaceIterator(Transform3D tform, int level)
      Description copied from interface: Shape3D
      Get a surface iterator for this Shape3D, subdividing the surface. The surface iterator will represent the shape as a sequence of Bézier patches and Bézier triangles, with the order of the sequence arbitrary.

      Unless the transform is an affine transform, the transformation is not exact. In this case, the patches and triangles that constitute the surface after each is subdivided should be small enough that the transform can be approximated by an affine transform over the region containing the control points.

      Specified by:
      getSurfaceIterator in interface Shape3D
      Parameters:
      tform - a transform to apply to each control point; null for the identity transform
      level - the number of levels of partitioning (each additional level splits the previous level into quarters)
      Returns:
      a surface iterator
    • numberOfComponents

      public int numberOfComponents()
      Description copied from interface: Shape3D
      Get the number of components for this shape. Components are connected shapes - surfaces for which every point can connect to any other point.
      Specified by:
      numberOfComponents in interface Shape3D
      Returns:
      the number of components for this shape
    • getComponent

      public Shape3D getComponent(int i)
      Description copied from interface: Shape3D
      Get a component of this shape. Components are connected shapes - surfaces for which every point can connect to any other point. The components are referenced by an index, specified as an integer in the range [0,n), where n is the number of manifold components. If n is zero, no index is valid.
      Specified by:
      getComponent in interface Shape3D
      Parameters:
      i - the component's index
      Returns:
      a model containing the specified component
      See Also:
    • isWellFormed

      public boolean isWellFormed()
      Determine if the grid is well formed
      Returns:
      true if the grid is well formed; false otherwise
    • isWellFormed

      public boolean isWellFormed(Appendable out)
      Determine if the grid is well formed, logging error messages to an Appendable
      Parameters:
      out - an Appendable for logging error messages
      Returns:
      true if the grid is well formed; false otherwise
    • createConnectionsTo

      public BezierGrid[] createConnectionsTo(BezierGrid grid) throws IllegalStateException
      Create Bézier grids that will connect this grid to a specified grid. The indices of matching vertices on the boundaries of the two grids must be the same. The number of vertices for the connecting grids along their U axes is 2. For their V axes, the number varies, with each grid matching part of a boundary of this grid. The number of grids that are returned equals the number of disjoint curves that make up the boundary of this grid.
      Parameters:
      grid - the grid to which this grid should be connected.
      Returns:
      the grids that will connect corresponding components of boundaries of this grid and the specified grid
      Throws:
      IllegalStateException - this grid is not well formed or its boundary cannot be computed.
    • createConnectionsTo

      public BezierGrid[] createConnectionsTo(BezierGrid grid, int n) throws IllegalStateException
      Create Bézier grids, with a specified number of vertices in the 'U' direction, that will connect this grid to a specified rid. The indices of matching vertices on the boundaries of the two grids must be the same. The number of vertices for the connecting grids along their U axes is n. For their V axes, the number varies, with each grid matching part of a boundary of this grid.
      Parameters:
      grid - the grid to which this grid should be connected.
      n - the number of vertices for the connecting grids along their U axes
      Returns:
      the grids that will connect corresponding components of boundaries of this grid and the specified grid
      Throws:
      IllegalStateException - this grid is not well formed or its boundary cannot be computed.
    • createConnectionsTo

      public BezierGrid[] createConnectionsTo(BezierGrid grid, boolean split) throws IllegalStateException
      Create Bézier grids that will connect this grid to a specified grid, optionally splitting the returned grids into multiple grids. The indices of matching vertices on the boundaries of the two grids must be the same. The number of vertices for the connecting grids along their U axes is 2. For their V axes, the number varies, with each grid matching part of a boundary of this grid. The number of grids that are returned equals the number of disjoint curves that make up the boundary of this grid when the argument split is false. When split is true, the number of grids is the number of splines that make up the boundary.

      When the 'split' argument has the value true, and intermediate control points for a grid's edges in the 'U' direction are explicitly modified, one may have to add additional B@eacute;zier patches if the grids are to be connected to each other. The typical case for setting 'split' to true is when adding such patches is desired.

      Parameters:
      grid - the grid to which this grid should be connected.
      split - true if there can be multiple grids per boundary component; false otherwise
      Returns:
      the grids that will connect corresponding components of boundaries of this grid and the specified grid
      Throws:
      IllegalStateException - this grid is not well formed or its boundary cannot be computed.
    • createConnectionsTo

      public BezierGrid[] createConnectionsTo(BezierGrid grid, boolean split, int... indices) throws IllegalStateException
      Create Bézier grids that will connect this grid to a specified grid, optionally splitting the returned grids into multiple grids, and restricting the returned grids to ones that match a specified boundary. The indices of matching vertices on the boundaries of the two grids must be the same. The number of vertices for the connecting grids along their U axes is 2. For their V axes, the number varies, with each grid matching part of a boundary of this grid. The number of grids that are returned equals the number of disjoint curves that make up the boundary of this grid when the argument split is false. When split is true, the number of grids is the number of splines that make up the boundary.

      When the 'split' argument has the value true, and intermediate control points for a grid's edges in the 'U' direction are explicitly modified, one may have to add additional Bézier patches if the grids are to be connected to each other. The typical case for setting 'split' to true is when adding such patches is desired.

      The final arguments are pairs of U-V indices indicating vertices that are part of this grid's boundary. Those boundary components that match any of these pairs will be connected by the generated grids, whereas other boundary components will not be connected.

      Parameters:
      grid - the grid to which this grid should be connected.
      split - true if there can be multiple grids per boundary component; false otherwise
      indices - a sequence of pairs of U and V indices respectively for vertices along components of this grid's boundary
      Returns:
      the grids that will connect corresponding components of boundaries of this grid and the specified grid
      Throws:
      IllegalStateException - this grid is not well formed or its boundary cannot be computed.
    • createConnectionsTo

      public BezierGrid[] createConnectionsTo(BezierGrid grid, int n, boolean split)
      Create Bézier grids that will connect this grid to a specified grid, specifying the number of vertices along a connecting grid's U axis and optionally splitting the returned grids into multiple grids. The indices of matching vertices on the boundaries of the two grids must be the same. The number of vertices for the connecting grids along their U axes must be at least 2 and is specified by this method's second argument. For their V axes, the number varies, with each grid matching part of a boundary of this grid. The number of grids that are returned equals the number of disjoint curves that make up the boundary of this grid when the argument split is false. When split is true, the number of grids is the number of splines that make up the boundary.

      When the 'split' argument has the value true, and either the intermediate control points for a grid's edges in the 'U' direction are explicitly modified or the number of vertices in the U direction are larger than two, one may have to add additional Bézier patches if the grids are to be connected to each other. The typical case for setting 'split' to true is when adding such patches is desired.

      Parameters:
      grid - the grid to which this grid should be connected.
      n - the number of vertices along the U axis for each of the grids that this method creates
      split - true if there can be multiple grids per boundary component; false otherwise
      Returns:
      the grids that will connect corresponding components of boundaries of this grid and the specified grid
      Throws:
      IllegalStateException - this grid is not well formed or its boundary cannot be computed.
    • createConnectionsTo

      public BezierGrid[] createConnectionsTo(BezierGrid grid, int n, boolean split, int... indices) throws IllegalStateException, IllegalArgumentException
      Create Bézier grids that will connect this grid to a specified grid, specifying the number of vertices along a connecting grid's U axis, optionally splitting the returned grids into multiple grids, and specifying pairs of indices for vertices along allowed boundaries. The indices of matching vertices on the boundaries of the two grids must be the same. The number of vertices for the connecting grids along their U axes must be at least 2 and is specified by this method's second argument. For their V axes, the number varies, with each grid matching part of a boundary of this grid. The number of grids that are returned equals the number of disjoint curves that make up the boundary of this grid when the argument split is false. When split is true, the number of grids is the number of splines that make up the boundary.

      When the 'split' argument has the value true, and either the intermediate control points for a grid's edges in the 'U' direction are explicitly modified or the number of vertices in the U direction are larger than two, one may have to add additional Bézier patches if the grids are to be connected to each other. The typical case for setting 'split' to true is when adding such patches is desired.

      The final arguments are pairs of U-V indices indicating vertices that are part of this grid's boundary. Those boundary components that match any of these pairs will be connected by the generated grids, whereas other boundary components will not be connected. For each grid that is generated the 'V' index of the generated grid will increase as one traverses along the boundary from the starting point specified by the indices, and the u=0 edge of each generated grid will match its corresponding boundary.

      Parameters:
      grid - the grid to which this grid should be connected.
      n - the number of vertices along the U axis for each of the grids that this method creates
      split - true if there can be multiple grids per boundary component; false otherwise
      indices - a sequence of pairs of U and V indices respectively for vertices along components of this grid's boundary
      Returns:
      the grids that will connect corresponding components of boundaries of this grid and the specified grid
      Throws:
      IllegalStateException - this grid is not well formed or its boundary cannot be computed.
      IllegalArgumentException
    • createConnectionsTo

      public BezierGrid[] createConnectionsTo(BezierGrid grid, int n, boolean split, boolean exclude, int... indices) throws IllegalStateException, IllegalArgumentException
      Create Bézier grids that will connect this grid to a specified grid, specifying the number of vertices along a connecting grid's U axis and optionally splitting the returned grids into multiple grids, and specifying pairs of indices for vertices along allowed or disallowed boundaries. The indices of matching vertices on the boundaries of the two grids must be the same. The number of vertices for the connecting grids along their U axes must be at least 2 and is specified by this method's second argument. For their V axes, the number varies, with each grid matching part of a boundary of this grid. The number of grids that are returned equals the number of disjoint curves that make up the boundary of this grid when the argument split is false. When split is true, the number of grids is the number of splines that make up the boundary.

      When the 'split' argument has the value true, and either the intermediate control points for a grid's edges in the 'U' direction are explicitly modified or the number of vertices in the U direction are larger than two, one may have to add additional Bézier patches if the grids are to be connected to each other. The typical case for setting 'split' to true is when adding such patches is desired.

      The final arguments are pairs of U-V indices indicating vertices that are either part of this grid's boundary or part of this grid's boundary that are excluded. When the 'exclude' argument is false, those boundary components that match any of these pairs will be connected to the generated grids, whereas other boundary components will not be connected. For the ones that are connected, the u=0 edge of the generated grid will match the corresponding boundary of this grid. The u=0, v= 0 corner of each generated grid will match the point on this grid's boundary corresponding to the specified pair of indices. When the 'exclude' argument is 'true', the indices indicate which component of the boundary are not connected, and in this case the starting point for the boundary is not specified and will in general be hard to predict.

      Parameters:
      grid - the grid to which this grid should be connected.
      n - the number of vertices along the U axis for each of the grids that this method creates
      split - true if there can be multiple grids per boundary component; false otherwise
      exclude - true if each pair of indices denotes a vertex along a component of the boundary that is excluded; false if each pair of indices denotes a vertex along a component of the boundary that is included
      indices - a sequence of pairs of U and V indices respectively for vertices along components of this grid's boundary
      Returns:
      the grids that will connect corresponding components of boundaries of this grid and the specified grid
      Throws:
      IllegalStateException - this grid is not well formed or its boundary cannot be computed.
      IllegalArgumentException
    • createExtensionGrid

      public BezierGrid createExtensionGrid(Point3DMapper<Point3D> mapping, int[] regionChanges, int n, int uIndex, int vIndex) throws IllegalStateException, IllegalArgumentException
      Create an extension to a Bézier grid based on a mapping function. This method creates a new BezierGrid. The number of grid elements in the new grid's V direction are determined by a component of the boundary of this grid. That component will a closed, continuous path that passes through the grid point whose U-V indices are (uIndex, vIndex). If the point at (uIndex, vIndex) is not on the boundary, null is returned; Otherwise the boundary that is used is the component of the full boundary that contains the point corresponding to (uIndex, vIndex). This component will be shifted so that it's first segment (its SEG_MOVETO segment) has coordinates equal to the value of the grid point corresponding to the indices (uIndex, vIndex). This point will be located at indices (0,0) in the extension grid, with increasing V values following the boundary.

      The grid returned will be frozen. The grid points and intermediate control points in the V direction are determined by the mapping function. Splines determine the intermediate control points in the U direction. For a fixed value of V, splines in the U direction or terminated or started at U indices specified by the second argument (regionChanges).

      The mapping function takes the following arguments:

      • i. This argument is the index in the U direction. Its values are in the range (0, n).
      • p. This argument is a grid point for which U is zero.
      • p1. This argument is optional. When present, the argument p is a control point that is not end point of a segment that is part of the boundary. p1 will be the starting point of the segment containing p.
      • p2. This argument is optional. When present, the argument p is a control point that is not an end point of a segment that is part of the boundary. p2 will be the ending point of the segment containing p.
      If p1 or p2 is provided, the other must be provided as well. These optional arguments are implemented by a variable argument whose type is Point3D, so the implementation of the mapping function will have as its last argument an array of length 0 or 2.
      Parameters:
      mapping - the mapping function
      regionChanges - a list of indices for the U direction for which the grid that is created changes regions (this argument is an array that may be modified by sorting it into ascending order).
      n - the number of grid points in the U direction
      uIndex - the U-direction index for a point on this grid that is part of this grid's boundary.
      vIndex - the V-direction index for a point on this grid that is part of this grid's boundary.
      Returns:
      a BezierGrid; null if (uIndex, vIndex) is not on a boundary.
      Throws:
      IllegalStateException
      IllegalArgumentException
    • getBoundary

      public Path3D getBoundary()
      Description copied from interface: Shape3D
      Get the boundary for this Shape3D. For a closed surface, the boundary will be an empty path.

      Typically, a boundary will consist of a series of distinct closed subpaths. Subpaths are separated by segments whose type is {link PathIterator3D#SEG_MOVETO}. For a closed manifold, the boundary will be an empty path.

      Specified by:
      getBoundary in interface Shape3D
      Returns:
      the boundary of this surface; null if a boundary cannot be computed
      See Also:
    • getBoundary

      public Path3D getBoundary(int... indices) throws IllegalStateException, IllegalArgumentException
      Get the boundary components that pass through specific grid points. The indices that are specified are pairs of indices giving the U-index and V-index respectively for a point on the grid. The path returned will consist of a concatenation of these boundary components, each modified so it starts at the point corresponding to a pair of indices. The order of these components may not be same as the order of the index pairs.
      Parameters:
      indices - the indices
      Returns:
      the boundary components, concatenated into a single path
      Throws:
      IllegalStateException
      IllegalArgumentException
    • isClosedManifold

      public boolean isClosedManifold()
      Description copied from interface: Shape3D
      Determine if this Shape3D is a closed two-dimensional manifold.
      Specified by:
      isClosedManifold in interface Shape3D
      Returns:
      true if the surface is a closed two-dimensional manifold; false otherwise
    • getBounds

      public Rectangle3D getBounds()
      Description copied from interface: Shape3D
      Get a bounding rectangular cuboid for a 3D shape. The edges will be aligned with the X, Y and Z axes. The cuboid created may not be the smallest one possible (for example, shapes defined by Bézier surfaces may just use the control points to determine the cuboid as the convex hull for the control points includes all of the surface for parameters in the normal range [0,1]).
      Specified by:
      getBounds in interface Shape3D
      Returns:
      a bounding rectangular cuboid for this Shape3D; null if the shape does not contain any points
    • isOriented

      public boolean isOriented()
      Description copied from interface: Shape3D
      Determine if a surface is oriented.
      Specified by:
      isOriented in interface Shape3D
      Returns:
      true if the surface has an orientation; false if it does not
    • setColor

      public void setColor(Color c)
      Set the color for all patches on this grid.
      Parameters:
      c - the color; null if a color is not specified
    • setColor

      public void setColor(int i, int j, Color c) throws IllegalArgumentException
      Set the color for a patch on this grid. The indices must be non-negative. For an index pair (i,j), i must be less than the number of U values on the grid and j must be less than the number of V values on the grid. Indices start at 0.
      Parameters:
      i - the index for the U direction
      j - the index for the V direction
      c - the color; null if a color is not specified
      Throws:
      IllegalArgumentException - an integer argument was out of range
    • setColor

      public void setColor(int i, int j, int w, int h, Color c) throws IllegalArgumentException
      Set the color for all patches on this grid. The indices must be non-negative. For an index pair (i,j), i must be less than the number of U values on the grid and j must be less than the number of V values on the grid. Indices start at 0. Both w and h must be non-negative. In addition, the values of i+w and j+h must not exceed the number of grid points in the U and V directions respectively.
      Parameters:
      i - the index for the U direction
      j - the index for the V direction
      w - the number of indices in the U direction
      h - the number of indices in the V diction
      c - the color; null if a color is not specified
      Throws:
      IllegalArgumentException - an integer argument was out of range