Package toxi.geom.nurbs

Source Code of toxi.geom.nurbs.NurbsCreator

/*
* jgeom: Geometry Library fo Java
*
* Copyright (C) 2005  Samuel Gerber
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License
* as published by the Free Software Foundation; either version 2
* of the License, or (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.
*/
package toxi.geom.nurbs;

import toxi.geom.Axis3D;
import toxi.geom.GMatrix;
import toxi.geom.GVector;
import toxi.geom.Origin3D;
import toxi.geom.ReadonlyVec3D;
import toxi.geom.SingularMatrixException;
import toxi.geom.Vec3D;
import toxi.geom.Vec4D;
import toxi.math.MathUtils;

/**
* This class offers some static methods to create NurbsSurfaces and NurbsCurves
* from diffrent inputs.
*
* @author sg
* @version 1.0
*/
public final class NurbsCreator {

    private static KnotVector averaging(final float[] uk, final int p) {
        int m = uk.length + p;
        int n = uk.length - 1;
        float ip = 1f / p;
        float[] u = new float[m + 1];
        for (int i = 0; i <= p; i++) {
            u[m - i] = 1;
        }
        for (int j = 1; j <= n - p; j++) {
            float sum = 0;
            for (int i = j; i <= j + p - 1; i++) {
                sum += uk[i];
            }
            u[j + p] = sum * ip;
        }
        return new KnotVector(u, p);
    }

    private static float[] centripetal(Vec3D[] points) {
        int n = points.length - 1;
        float d = 0;
        float[] uk = new float[n + 1];
        uk[n] = 1;
        double[] tmp = new double[n];
        for (int k = 1; k <= n; k++) {
            tmp[k - 1] = Math.sqrt(points[k].distanceTo(points[k - 1]));
            d += tmp[k - 1];
        }
        d = 1f / d;
        for (int i = 1; i < n; i++) {
            uk[i] = uk[i - 1] + (float) (tmp[i - 1] * d);
        }
        return uk;
    }

    /**
     * Create an Arc.
     *
     * @param o
     *            Origin to creat arc around
     * @param r
     *            Radius of the arc.
     * @param thetaStart
     *            Start angle of the arc in radians
     * @param thetaEnd
     *            End angle of the arc in radians. If end angle is smaller than
     *            start angle, the end angle is increased by 2*PI.
     * @return A NurbsCurve for the Arc.
     */
    public static NurbsCurve createArc(Origin3D o, float r, float thetaStart,
            float thetaEnd) {
        Vec3D tmp = new Vec3D();

        if (thetaEnd < thetaStart) {
            thetaEnd += MathUtils.TWO_PI;
        }
        double theta = thetaEnd - thetaStart;

        int narcs = 4;
        if (theta <= MathUtils.HALF_PI) {
            narcs = 1;
        } else if (theta <= MathUtils.PI) {
            narcs = 2;
        } else if (theta <= MathUtils.THREE_HALVES_PI) {
            narcs = 3;
        }
        double dtheta = theta / narcs;
        int n = 2 * narcs;
        double w1 = Math.cos(dtheta / 2);

        final float sinStart = (float) Math.sin(thetaStart);
        final float cosStart = (float) Math.cos(thetaStart);
        tmp.set(o.xAxis).scaleSelf(r * cosStart);
        Vec3D p0 = new Vec3D(o.origin).addSelf(tmp);
        tmp.set(o.yAxis).scaleSelf(r * sinStart);
        p0.addSelf(tmp);

        tmp.set(o.yAxis).scaleSelf(cosStart);
        Vec3D t0 = new Vec3D(o.xAxis).scaleSelf(-sinStart).addSelf(tmp);

        Vec4D[] cps = new Vec4D[n + 1];
        cps[0] = new Vec4D(p0, 1);
        int index = 0;
        double angle = thetaStart;

        Vec3D p1 = new Vec3D();
        Vec3D p2 = new Vec3D();
        Vec3D t2 = new Vec3D();
        for (int i = 1; i <= narcs; i++) {
            angle += dtheta;
            final double sin = Math.sin(angle);
            final double cos = Math.cos(angle);

            tmp.set(o.xAxis).scaleSelf((float) (r * cos));
            p2.set(o.origin).addSelf(tmp);
            tmp.set(o.yAxis).scaleSelf((float) (r * sin));
            p2.addSelf(tmp);

            cps[index + 2] = new Vec4D(p2, 1);

            t2.set(o.xAxis).scaleSelf((float) -sin);
            tmp.set(o.yAxis).scaleSelf((float) cos);
            t2.addSelf(tmp);

            lineIntersect3D(p0, t0, p2, t2, p1, p1);

            cps[index + 1] = new Vec4D(p1, (float) w1);
            index += 2;
            if (i < narcs) {
                p0.set(p2);
                t0.set(t2);
            }
        }
        int j = n + 1;
        float[] uKnot = new float[j + 3];
        for (int i = 0; i < 3; i++) {
            uKnot[i + j] = 1;
        }
        switch (narcs) {
            case 2:
                uKnot[3] = 0.5f;
                uKnot[4] = 0.5f;
                break;
            case 3:
                uKnot[3] = uKnot[4] = MathUtils.THIRD;
                uKnot[5] = uKnot[6] = 2 * MathUtils.THIRD;
                break;
            case 4:
                uKnot[3] = 0.25f;
                uKnot[4] = 0.25f;
                uKnot[5] = 0.5f;
                uKnot[6] = 0.5f;
                uKnot[7] = 0.75f;
                uKnot[8] = 0.75f;
                break;
        }

        return new BasicNurbsCurve(cps, uKnot, 2);
    }

    /**
     * Create a full-circle NurbsCurve around the given Origin with radius r.
     * The NurbsCurve has controlpolygon which has 7 controlpoints and the shape
     * of quadrat.
     *
     * @param o
     *            Origin to create the full-circle around
     * @param r
     *            Radius of the full-circle
     * @return A NurbsCurve for a full-circle
     */
    public static NurbsCurve createFullCircleQuad7(Origin3D o, float r) {

        Vec4D[] cp = new Vec4D[7];
        cp[0] = new Vec4D(o.xAxis.scale(r), 1);
        cp[3] = cp[0].getInvertedXYZ();
        cp[6] = cp[0].copy();

        cp[1] = new Vec4D(o.yAxis.add(o.xAxis).scaleSelf(r), 0.5f);
        cp[4] = cp[1].getInvertedXYZ();

        cp[2] = new Vec4D(o.xAxis.getInverted().addSelf(o.yAxis).scaleSelf(r),
                0.5f);
        cp[5] = cp[2].getInvertedXYZ();

        for (int i = 0; i < 7; i++) {
            cp[i].addXYZSelf(o.origin);
        }
        float[] u = {
                0, 0, 0, 0.25f, 0.5f, 0.5f, 0.75f, 1, 1, 1
        };
        return new BasicNurbsCurve(cp, u, 2);
    }

    /**
     * Create a full-circle NurbsCurve around the given Origin with radius r.
     * The NurbsCurve has controlpolygon which has 9 controlpoints and the shape
     * of quadrat.
     *
     * @param o
     *            Origin to create the full-circle around
     * @param r
     *            Radius of the full-circle
     * @return A NurbsCurve for a full-circle
     */
    public static NurbsCurve createFullCircleQuad9(Origin3D o, float r) {
        final float w = MathUtils.SQRT2 / 2;

        Vec4D[] cp = new Vec4D[9];
        cp[0] = new Vec4D(o.xAxis.scale(r), 1);
        cp[4] = cp[0].getInvertedXYZ();
        cp[8] = cp[0].copy();

        cp[1] = new Vec4D(o.xAxis.add(o.yAxis).scaleSelf(r), w);
        cp[5] = cp[1].getInvertedXYZ();

        cp[2] = new Vec4D(o.yAxis.scale(r), 1);
        cp[6] = cp[2].getInvertedXYZ();

        cp[3] = new Vec4D(o.xAxis.getInverted().addSelf(o.yAxis).scaleSelf(r),
                w);
        cp[7] = cp[3].getInvertedXYZ();

        for (int i = 0; i < 9; i++) {
            cp[i].addXYZSelf(o.origin);
        }
        float[] u = {
                0, 0, 0, 0.25f, 0.25f, 0.5f, 0.5f, 0.75f, 0.75f, 1, 1, 1
        };
        return new BasicNurbsCurve(cp, u, 2);
    }

    /**
     * Create a revolved NurbsSurface from the given NurbsCurve around the given
     * axis whith the angle theta.
     *
     * @param a
     *            Axis to revolve around.
     * @param curve
     *            NurbsCurve to revolve
     * @param theta
     *            Angle to revolve
     * @return The revolved NurbsSurface
     */
    // TODO:call createRevolvedSurface(Axis3D a, NurbsCurve curve, double
    // thetaStart, double thetaEnd) as as it is tested
    public static NurbsSurface createRevolvedSurface(Axis3D a,
            NurbsCurve curve, double theta) {
        int narcs = 4;
        if (theta <= MathUtils.HALF_PI) {
            narcs = 1;
        } else if (theta <= MathUtils.PI) {
            narcs = 2;
        } else if (theta <= MathUtils.THREE_HALVES_PI) {
            narcs = 3;
        }

        int j = 3 + 2 * (narcs - 1);
        final double dtheta = theta / narcs;
        final float[] uKnot = new float[j + 3];
        for (int i = 0; i < 3; i++) {
            uKnot[j + i] = 1;
        }
        switch (narcs) {
            case 2:
                uKnot[3] = 0.5f;
                uKnot[4] = 0.5f;
                break;
            case 3:
                uKnot[3] = uKnot[4] = MathUtils.THIRD;
                uKnot[5] = uKnot[6] = 2 * MathUtils.THIRD;
                break;
            case 4:
                uKnot[3] = 0.25f;
                uKnot[4] = 0.25f;
                uKnot[5] = 0.5f;
                uKnot[6] = 0.5f;
                uKnot[7] = 0.75f;
                uKnot[8] = 0.75f;
                break;
        }

        double angle = 0;
        final double[] cos = new double[narcs + 1];
        final double[] sin = new double[narcs + 1];
        for (int i = 0; i <= narcs; i++) {
            cos[i] = Math.cos(angle);
            sin[i] = Math.sin(angle);
            angle += dtheta;
        }

        Vec4D[] pj = curve.getControlPoints();
        Vec3D P0 = new Vec3D();
        final Vec3D P2 = new Vec3D();
        final Vec3D O = new Vec3D();
        final Vec3D T2 = new Vec3D();
        final Vec3D T0 = new Vec3D();
        final Vec3D tmp = new Vec3D();
        final Vec3D X = new Vec3D();
        final Vec3D Y = new Vec3D();
        final Vec4D[][] pij = new Vec4D[2 * narcs + 1][pj.length];
        final double wm = Math.cos(dtheta / 2);
        for (j = 0; j < pj.length; j++) {
            pointToLine3D(a.origin, a.dir, pj[j].to3D(), O);
            X.set(pj[j].to3D().subSelf(O));
            final double r = X.magnitude();
            if (r == 0) {
                X.set(O);
            }
            X.normalize();
            a.dir.crossInto(X, Y);
            pij[0][j] = new Vec4D(pj[j]);
            P0 = pj[j].to3D();
            T0.set(Y);
            int index = 0;
            for (int i = 1; i <= narcs; i++) {
                tmp.set(X).scaleSelf((float) (r * cos[i]));
                P2.set(O).addSelf(tmp);
                tmp.set(Y).scaleSelf((float) (r * sin[i]));
                P2.addSelf(tmp);

                pij[index + 2][j] = new Vec4D(P2, pj[j].w);

                tmp.set(Y).scaleSelf((float) cos[i]);
                T2.set(X).scaleSelf((float) -sin[i]).addSelf(tmp);

                lineIntersect3D(P0, T0, P2, T2, tmp, tmp);
                pij[index + 1][j] = new Vec4D(tmp, (float) (wm * pj[j].w));

                index += 2;
                if (i < narcs) {
                    P0.set(P2);
                    T0.set(T2);
                }

            }
        }
        ControlNet cnet = new ControlNet(pij);
        return new BasicNurbsSurface(cnet, uKnot, curve.getKnots(), 2,
                curve.getDegree());
    }

    /**
     * Create a revolved NurbsSurface from the given NurbsCurve around the given
     * axis whith the angle theta.
     *
     * @param a
     *            Axis to revolve around.
     * @param curve
     *            NurbsCurve to revolve
     * @param thetaStart
     *            Angle to start revolution
     * @param thetaEnd
     *            Angle to end revolution
     * @return The revolved NurbsSurface
     */
    public static NurbsSurface createRevolvedSurface(Axis3D a,
            NurbsCurve curve, double thetaStart, double thetaEnd) {
        int narcs = 4;
        if (thetaStart > thetaEnd) {
            double tmp = thetaEnd;
            thetaEnd = thetaStart;
            thetaStart = tmp;
        }
        double theta = thetaEnd - thetaStart;
        if (theta <= MathUtils.HALF_PI) {
            narcs = 1;
        } else if (theta <= MathUtils.PI) {
            narcs = 2;
        } else if (theta <= MathUtils.THREE_HALVES_PI) {
            narcs = 3;
        }

        int j = 3 + 2 * (narcs - 1);
        final double dtheta = theta / narcs;
        final float[] uKnot = new float[j + 3];
        for (int i = 0; i < 3; i++) {
            uKnot[i] = 0;
            uKnot[j + i] = 1;
        }
        switch (narcs) {
            case 2:
                uKnot[3] = 0.5f;
                uKnot[4] = 0.5f;
                break;
            case 3:
                uKnot[3] = uKnot[4] = MathUtils.THIRD;
                uKnot[5] = uKnot[6] = 2 * MathUtils.THIRD;
                break;
            case 4:
                uKnot[3] = 0.25f;
                uKnot[4] = 0.25f;
                uKnot[5] = 0.5f;
                uKnot[6] = 0.5f;
                uKnot[7] = 0.75f;
                uKnot[8] = 0.75f;
                break;
        }

        double angle = thetaStart;
        final double[] cos = new double[narcs + 1];
        final double[] sin = new double[narcs + 1];
        for (int i = 0; i <= narcs; i++) {
            cos[i] = Math.cos(angle);
            sin[i] = Math.sin(angle);
            angle += dtheta;
        }

        final Vec4D[] pj = curve.getControlPoints();
        Vec3D P0 = new Vec3D();
        final Vec3D O = new Vec3D();
        final Vec3D P2 = new Vec3D();
        final Vec3D T2 = new Vec3D();
        final Vec3D T0 = new Vec3D();
        final Vec3D tmp = new Vec3D();
        final Vec3D X = new Vec3D();
        final Vec3D Y = new Vec3D();
        final Vec4D[][] pij = new Vec4D[2 * narcs + 1][pj.length];
        final double wm = Math.cos(dtheta / 2);
        for (j = 0; j < pj.length; j++) {
            pointToLine3D(a.origin, a.dir, pj[j].to3D(), O);
            X.set(pj[j].to3D().subSelf(O));
            final double r = X.magnitude();
            if (r == 0) {
                X.set(O);
            }
            X.normalize();
            a.dir.crossInto(X, Y);
            pij[0][j] = new Vec4D(pj[j]);
            P0 = pj[j].to3D();
            T0.set(Y);
            int index = 0;
            for (int i = 1; i <= narcs; i++) {
                tmp.set(X).scaleSelf((float) (r * cos[i]));
                P2.set(O).addSelf(tmp);
                tmp.set(Y).scaleSelf((float) (r * sin[i]));
                P2.addSelf(tmp);

                pij[index + 2][j] = new Vec4D(P2, pj[j].w);

                tmp.set(Y).scaleSelf((float) cos[i]);
                T2.set(X).scaleSelf((float) -sin[i]).addSelf(tmp);

                lineIntersect3D(P0, T0, P2, T2, tmp, tmp);
                pij[index + 1][j] = new Vec4D(tmp, (float) (wm * pj[j].w));

                index += 2;
                if (i < narcs) {
                    P0.set(P2);
                    T0.set(T2);
                }
            }
        }
        ControlNet cnet = new ControlNet(pij);
        return new BasicNurbsSurface(cnet, uKnot, curve.getKnots(), 2,
                curve.getDegree());
    }

    /**
     * Create a semi-circle NurbsCurve around the given Origin with radius r.
     *
     * @param o
     *            Origin to create semi-circle around.
     * @param r
     *            Radius of the semi-circle
     * @return A NurbsCurve for a semi-circle
     */
    public static NurbsCurve createSemiCircle(Origin3D o, float r) {
        Vec4D[] cp = new Vec4D[4];
        cp[0] = new Vec4D(o.xAxis.scale(r), 1);
        cp[3] = cp[0].getInvertedXYZ();
        cp[0].addXYZSelf(o.origin);
        cp[3].addXYZSelf(o.origin);
        cp[1] = new Vec4D(o.xAxis.add(o.yAxis).scaleSelf(r).addSelf(o.origin),
                0.5f);
        cp[2] = new Vec4D(o.xAxis.getInverted().addSelf(o.yAxis).scaleSelf(r)
                .addSelf(o.origin), 0.5f);

        float[] u = {
                0, 0, 0, 0.5f, 1, 1, 1
        };
        return new BasicNurbsCurve(cp, u, 2);
    }

    /**
     * Creates a {@link NurbsSurface} by swinging a profile {@link NurbsCurve}
     * in the XZ plane around a trajectory curve in the XY plane. Both curves
     * MUST be offset from the major axes (i.e. their control points should have
     * non-zero coordinates for the Y coordinates of the profile curve and the Z
     * coordinates of the trajectory).
     *
     * @param proj
     *            profile curve in XZ
     * @param traj
     *            trajectory curve in XY
     * @param alpha
     *            scale factor
     * @return 3D NURBS surface
     */
    public static NurbsSurface createSwungSurface(NurbsCurve proj,
            NurbsCurve traj, float alpha) {
        Vec4D[] cpProj = proj.getControlPoints();
        Vec4D[] cpTraj = traj.getControlPoints();

        // The NURBS Book, Piegl, p.455,456
        // http://books.google.co.uk/books?id=7dqY5dyAwWkC&pg=PA455&lpg=PA455
        // fixed Z handling (was wrong in original jgeom version)
        Vec4D[][] cps = new Vec4D[cpProj.length][cpTraj.length];
        for (int i = 0; i < cpProj.length; i++) {
            for (int j = 0; j < cpTraj.length; j++) {
                Vec4D cp = new Vec4D();
                cp.x = cpProj[i].x * cpTraj[j].x * alpha;
                cp.y = cpProj[i].y * cpTraj[j].y * alpha;
                cp.z = (cpProj[i].z + cpTraj[j].z) * alpha;
                cp.w = cpProj[i].w * cpTraj[j].w;
                cps[i][j] = cp;
            }
        }
        return new BasicNurbsSurface(new ControlNet(cps), proj.getKnots(),
                traj.getKnots(), proj.getDegree(), traj.getDegree());

    }

    /**
     * Perform a linear extrusion of the given {@link NurbsCurve} along the
     * supplied vector to produce a new {@link NurbsSurface}. The extrusion
     * length is the length of the vector given.
     *
     * @param curve
     *            NURBS curve instance
     * @param extrude
     *            a extrusion vector
     * @return a NurbsSurface.
     */
    public static NurbsSurface extrudeCurve(NurbsCurve curve, Vec3D extrude) {

        // Curve and Surface Construction using Rational B-splines
        // Piegl and Tiller CAD Vol 19 #9 November 1987 pp 485-498
        KnotVector vKnot = new KnotVector(new float[] {
                0f, 0f, 1f, 1f
        }, 1);

        Vec4D[][] cpoints = new Vec4D[curve.getControlPoints().length][2];
        Vec4D[] curvePoints = curve.getControlPoints();
        for (int i = 0; i < cpoints.length; i++) {
            for (int j = 0; j < 2; j++) {
                /*
                 * Change added 11/02/90 Steve Larkin : Have multiplied the term
                 * wcoord to the extrusion vector before adding to the curve
                 * coordinates. Not really sure this is the correct fix, but it
                 * works !
                 */
                Vec4D cp = new Vec4D();
                cp.x = curvePoints[i].x + j * extrude.x;
                cp.y = curvePoints[i].y + j * extrude.y;
                cp.z = curvePoints[i].z + j * extrude.z;
                cp.w = curvePoints[i].w;
                cpoints[i][j] = cp;
            }
        }
        ControlNet cnet = new ControlNet(cpoints);
        return new BasicNurbsSurface(cnet, curve.getKnots(), vKnot.getArray(),
                curve.getDegree(), vKnot.getDegree());
    }

    /**
     * Interpolates a NurbCurve form the given Points using a global
     * interpolation technique.
     *
     * @param points
     *            Points to interpolate
     * @param degree
     *            degree of the interpolated NurbsCurve
     * @return A NurbsCurve interpolating the given Points
     * @throws InterpolationException
     *             thrown if interpolation failed or is not possible.
     */
    public static NurbsCurve globalCurveInterpolation(Vec3D[] points, int degree)
            throws InterpolationException {
        try {
            final int n = points.length;
            final double[] A = new double[n * n];

            final float[] uk = centripetal(points);
            KnotVector uKnots = averaging(uk, degree);
            for (int i = 0; i < n; i++) {
                int span = uKnots.findSpan(uk[i]);
                double[] tmp = uKnots.basisFunctions(span, uk[i]);
                System.arraycopy(tmp, 0, A, i * n + span - degree, tmp.length);
            }
            final GMatrix a = new GMatrix(n, n, A);
            final GVector perm = new GVector(n);
            final GMatrix lu = new GMatrix(n, n);
            a.computeLUD(lu, perm);

            final Vec4D[] cps = new Vec4D[n];
            for (int i = 0; i < cps.length; i++) {
                cps[i] = new Vec4D(0, 0, 0, 1);
            }

            // x-ccordinate
            final GVector b = new GVector(n);
            for (int j = 0; j < n; j++) {
                b.setElement(j, points[j].x);
            }
            final GVector sol = new GVector(n);
            sol.backSolveLUD(lu, b, perm);
            for (int j = 0; j < n; j++) {
                cps[j].x = (float) sol.get(j);
            }

            // y-ccordinate
            for (int j = 0; j < n; j++) {
                b.setElement(j, points[j].y);
            }
            sol.zero();
            sol.backSolveLUD(lu, b, perm);
            for (int j = 0; j < n; j++) {
                cps[j].y = (float) sol.get(j);
            }

            // z-ccordinate
            for (int j = 0; j < n; j++) {
                b.setElement(j, points[j].z);
            }
            sol.zero();
            sol.backSolveLUD(lu, b, perm);
            for (int j = 0; j < n; j++) {
                cps[j].z = (float) sol.get(j);
            }
            return new BasicNurbsCurve(cps, uKnots);
        } catch (SingularMatrixException ex) {
            throw new InterpolationException(ex);
        }

    }

    /**
     * Interpolates a NurbsSurface from the given points using a gloabl
     * interpolation technique.
     *
     * @param points
     *            Points arranged in a net (matrix) to interpolate
     * @param uDegrees
     *            degree in u direction
     * @param vDegrees
     *            degree in v direction
     * @return A NurbsSurface interpolating the given points.
     * @throws InterpolationException
     *             thrown if interpolation failed or is not possible.
     */
    public static NurbsSurface globalSurfaceInterpolation(Vec3D[][] points,
            int uDegrees, int vDegrees) throws InterpolationException {
        final int n = points.length;
        final int m = points[0].length;
        float[][] uv = surfaceMeshParameters(points, n - 1, m - 1);
        KnotVector u = averaging(uv[0], uDegrees);
        KnotVector v = averaging(uv[1], vDegrees);

        Vec4D[][] r = new Vec4D[m][n];
        Vec3D[] tmp = new Vec3D[n];
        for (int l = 0; l < m; l++) {
            for (int i = 0; i < n; i++) {
                tmp[i] = points[i][l];
            }
            try {
                NurbsCurve curve = globalCurveInterpolation(tmp, uDegrees);
                r[l] = curve.getControlPoints();
            } catch (InterpolationException ex) {
                for (int i = 0; i < tmp.length; i++) {
                    r[l][i] = new Vec4D(tmp[i], 1);
                }
            }

        }

        Vec4D[][] cp = new Vec4D[n][m];
        tmp = new Vec3D[m];
        for (int i = 0; i < n; i++) {
            for (int j = 0; j < m; j++) {
                tmp[j] = r[j][i].to3D();
            }
            try {
                NurbsCurve curve = globalCurveInterpolation(tmp, vDegrees);
                cp[i] = curve.getControlPoints();
            } catch (InterpolationException ex) {
                for (int j = 0; j < tmp.length; j++) {
                    cp[i][j] = new Vec4D(tmp[j], 1);
                }
            }
        }

        return new BasicNurbsSurface(new ControlNet(cp), u, v);
    }

    private static void lineIntersect3D(Vec3D p0, Vec3D t0, Vec3D p2, Vec3D t2,
            Vec3D out0, Vec3D out2) {
        Vec3D v02 = p0.sub(p2);

        double a = t0.dot(t0);
        double b = t0.dot(t2);
        double c = t2.dot(t2);
        double d = t0.dot(v02);
        double e = t2.dot(v02);
        double denom = a * c - b * b;

        double mu0, mu2;

        if (denom < MathUtils.EPS) {
            mu0 = 0;
            mu2 = b > c ? d / b : e / c;
        } else {
            mu0 = (b * e - c * d) / denom;
            mu2 = (a * e - b * d) / denom;
        }

        out0.set(t0.scale((float) mu0).addSelf(p0));
        out2.set(t2.scale((float) mu2).addSelf(p2));
    }

    private static void pointToLine3D(ReadonlyVec3D p, ReadonlyVec3D t,
            Vec3D top, Vec3D out) {
        Vec3D dir = top.sub(p);
        float hyp = dir.magnitude();
        out.set(p.add(t.scale(t.dot(dir.normalize()) * hyp)));
    }

    private static float[][] surfaceMeshParameters(Vec3D points[][], int n,
            int m) {
        final float[][] res = new float[2][];
        int num = m + 1;
        final float[] cds = new float[(n + 1) * (m + 1)];
        final float[] uk = new float[n + 1];
        uk[n] = 1;
        for (int l = 0; l <= m; l++) {
            float total = 0;
            for (int k = 1; k <= n; k++) {
                cds[k] = points[k][l].distanceTo(points[k - 1][l]);
                total += cds[k];
            }
            if (total == 0) {
                num = num - 1;
            } else {
                float d = 0;
                total = 1f / total;
                for (int k = 1; k <= n; k++) {
                    d += cds[k];
                    uk[k] += d * total;
                }
            }
        }
        if (num == 0) {
            return null;
        }
        float inum = 1f / num;
        for (int k = 1; k < n; k++) {
            uk[k] *= inum;
        }

        num = n + 1;
        final float[] vk = new float[m + 1];
        vk[m] = 1;
        for (int l = 0; l <= n; l++) {
            float total = 0;
            Vec3D[] pl = points[l];
            for (int k = 1; k <= m; k++) {
                cds[k] = pl[k].distanceTo(pl[k - 1]);
                total += cds[k];
            }
            if (total == 0) {
                num = num - 1;
            } else {
                float d = 0;
                total = 1f / total;
                for (int k = 1; k <= m; k++) {
                    d += cds[k];
                    vk[k] += d * total;
                }
            }
        }
        if (num == 0) {
            return null;
        }
        inum = 1f / num;
        for (int k = 1; k < m; k++) {
            vk[k] *= inum;
        }
        res[0] = uk;
        res[1] = vk;
        return res;
    }

    private NurbsCreator() {
    }
}
TOP

Related Classes of toxi.geom.nurbs.NurbsCreator

TOP
Copyright © 2018 www.massapi.com. All rights reserved.
All source code are property of their respective owners. Java is a trademark of Sun Microsystems, Inc and owned by ORACLE Inc. Contact coftware#gmail.com.