home *** CD-ROM | disk | FTP | other *** search
/ Late Night VRML 2.0 with Java CD-ROM / code.zip / Ch15 / NURBS / Nurbs.java < prev    next >
Encoding:
Java Source  |  1997-01-29  |  23.6 KB  |  759 lines

  1. /*
  2.  * Copyright (c) 1997 ORC Incorporated.  All Rights Reserved.
  3.  *
  4.  * Permission to use, copy, modify, and distribute this software
  5.  * and its documentation for NON-COMMERCIAL purposes and without
  6.  * fee is hereby granted provided that this copyright notice
  7.  * appears in all copies. Please contact <info@ocnus.com> for
  8.  * further information regarding copyright and licensing.
  9.  * This code is provided without warranty, either expressed or implied.
  10.  */
  11. /* 
  12.  * Portions of this code appear in the book
  13.  * "Late Night VRML 2.0 with Java", Ziff-Davis Press, 1997
  14.  *
  15.  * Nurbs.java
  16.  *
  17.  * author   Timothy F. Rohaly
  18.  * version  1.0, 01/15/97
  19.  */
  20.  
  21. package nurbs;
  22.  
  23.  
  24. /**
  25.  * NURBS curve and surface
  26.  * @author   Timothy F.  Rohaly
  27.  * @version  1.0, 1/15/97
  28.  */
  29. public class Nurbs implements Cloneable {
  30.  
  31.     protected Knot       u;
  32.     protected Knot       v;
  33.     protected ControlNet controlNet;
  34.  
  35.  
  36.     /**
  37.      * NURBS Constructor.
  38.      */
  39.     Nurbs() {
  40.         // Use of this form not recommended since it
  41.         // bypasses consistency checks.
  42.         // It is left here solely as an ease to development.
  43.     }
  44.  
  45.  
  46.     /**
  47.      * NURBS Constructor.
  48.      * @param u the U knot sequence
  49.      * @param v the V knot sequence
  50.      * @param controlNet the array of Point4 control points
  51.      * @exception java.lang.IllegalArgumentException when the
  52.      */
  53.     public Nurbs(Knot u, Knot v, ControlNet controlNet) {
  54.         //
  55.         // Check for consistency
  56.         //
  57.         String errorString = getClass().getName() + ":  " +
  58.                              "Number of knots in array must equal " +
  59.                              "order + number of control points";
  60.         if (u.numControlPoints != controlNet.numUControlPoints ||
  61.             v.numControlPoints != controlNet.numVControlPoints   )
  62.             throw new IllegalArgumentException(errorString);
  63.  
  64.         this.u          = u;
  65.         this.v          = v;
  66.         this.controlNet = controlNet;
  67.     }
  68.  
  69.  
  70.     /**
  71.      * Performs a deep copy of this NURBS.
  72.      * @return a new instance of Nurbs
  73.      */
  74.     public Object clone() {
  75.         try {
  76.             Nurbs n      = (Nurbs) super.clone();
  77.             n.u          = (Knot) u.clone();
  78.             n.v          = (Knot) v.clone();
  79.             n.controlNet = (ControlNet) controlNet.clone();
  80.             return n;
  81.         }
  82.         catch (CloneNotSupportedException e) {
  83.             String errorString = getClass().getName() + ":  " +
  84.                                  "CloneNotSupportedException " +
  85.                                  "for a Cloneable class";
  86.             throw new InternalError(errorString);  // this should never happen
  87.         }
  88.     }
  89.  
  90.  
  91.     /**
  92.      * Access the number of U knots.
  93.      * @return the number of U knots
  94.      */
  95.     public int getNumUKnots() {
  96.         return u.numKnots;
  97.     }
  98.  
  99.  
  100.     /**
  101.      * Access the number of V knots.
  102.      * @return the number of V knots
  103.      */
  104.     public int getNumVKnots() {
  105.         return v.numKnots;
  106.     }
  107.  
  108.  
  109.     /**
  110.      * Access the NURB order in U.
  111.      * @return the order in U of the NURB
  112.      */
  113.     public int getUOrder() {
  114.         return u.order;
  115.     }
  116.  
  117.  
  118.     /**
  119.      * Access the NURB order in V.
  120.      * @return the order in V of the NURB
  121.      */
  122.     public int getVOrder() {
  123.         return v.order;
  124.     }
  125.  
  126.  
  127.     /**
  128.      * Access the number of U control points.
  129.      * @return the number of U control points
  130.      */
  131.     public int getNumUControlPoints() {
  132.         return controlNet.numUControlPoints;
  133.     }
  134.  
  135.  
  136.     /**
  137.      * Access the number of V control points.
  138.      * @return the number of V control points
  139.      */
  140.     public int getNumVControlPoints() {
  141.         return controlNet.numVControlPoints;
  142.     }
  143.  
  144.  
  145.     /**
  146.      * Access the U knot sequence.
  147.      * @return the U knot sequence
  148.      */
  149.     public Knot getUKnot() {
  150.         return u;
  151.     }
  152.  
  153.  
  154.     /**
  155.      * Access the V knot sequence.
  156.      * @return the V knot sequence
  157.      */
  158.     public Knot getVKnot() {
  159.         return v;
  160.     }
  161.  
  162.  
  163.     /**
  164.      * Set the U knot sequence.
  165.      * @param u the new U knot sequence
  166.      */
  167.     public void setUKnot(Knot u) {
  168.         this.u = u;
  169.     }
  170.  
  171.  
  172.     /**
  173.      * Set the V knot sequence.
  174.      * @param v the new V knot sequence
  175.      */
  176.     public void setVKnot(Knot v) {
  177.         this.v = v;
  178.     }
  179.  
  180.  
  181.     /**
  182.      * Set the ControlNet.
  183.      * @param controlNet the new ControlNet
  184.      */
  185.     public void setControlNet(ControlNet controlNet) {
  186.         this.controlNet = controlNet;
  187.     }
  188.  
  189.  
  190.     /**
  191.      * Scale this NURBS uniformly.
  192.      * @param scale the scale
  193.      */
  194.     public void scale(float scale) {
  195.         controlNet.scale(scale);
  196.     }
  197.  
  198.  
  199.     /**
  200.      * Scale this NURBS non-uniformly.
  201.      * @param scale the scale
  202.      */
  203.     public void scale(float xscale, float yscale, float zscale) {
  204.         controlNet.scale(xscale, yscale, zscale);
  205.     }
  206.  
  207.  
  208.     /**
  209.      * Translate this NURBS.
  210.      * @param x the translation in X
  211.      * @param y the translation in Y
  212.      * @param z the translation in Z
  213.      */
  214.     public void translate(float x, float y, float z) {
  215.         controlNet.translate(x, y, z);
  216.     }
  217.  
  218.  
  219.     /**
  220.      * Rotate this NURBS.
  221.      * @param x the X component of the rotation axis
  222.      * @param y the Y component of the rotation axis
  223.      * @param z the Z component of the rotation axis
  224.      * @param theta the rotation in radians
  225.      */
  226.     public void rotate(float x, float y, float z, float theta) {
  227.         controlNet.rotate(x, y, z, theta);
  228.     }
  229.  
  230.  
  231.     /**
  232.      * Transpose this NURBS by swapping U and V.
  233.      */
  234.     public void transpose() {
  235.         Knot temp;
  236.  
  237.         temp = u;
  238.         u    = v;
  239.         v    = temp;
  240.  
  241.         controlNet.transpose();
  242.     }
  243.  
  244.  
  245.     /**
  246.      * Refine this NURBS in the U and V directions by inserting
  247.      * new knots and control points.
  248.      * Employs recursive subdivision using the Oslo algorithm.
  249.      * Refinement is done through recursive subdivision by adding
  250.      * uSegments knots in the U direction and vSegments knots in
  251.      * the V direction.  (This also adds uSegments*vSegments
  252.      * control points since the order remains constant.)
  253.      * @param uSegments the number of new control points
  254.      * @param vSegments the number of new control points
  255.      * @return the refined Nurbs
  256.      */
  257.     public Nurbs tessellate(int uSegments, int vSegments) {
  258.         //
  259.         // Declare the return Nurbs.  It initially refers
  260.         // to "this" to account for the case where
  261.         // uSegments == vSegments == 0
  262.         //
  263.         Nurbs temp = this;
  264.  
  265.         //
  266.         // Tesselate in U direction first
  267.         //
  268.         if (uSegments > 0) {
  269.             temp = this.tessellateU(uSegments);
  270. //          System.err.println("After Tesselate: " + temp);
  271.         }
  272.  
  273.         if (vSegments > 0) {
  274.             //
  275.             // If this is a surface, transpose (swap U, V),
  276.             // then tessellate in new U direction (= old V direction)
  277.             //
  278.             if (uSegments <=0)
  279.                 temp = (Nurbs) this.clone();
  280.             temp.transpose();
  281.  
  282.             Nurbs temp2 = temp.tessellateU(vSegments);
  283.  
  284.             //
  285.             // Transpose back to its original configuration
  286.             // and return
  287.             //
  288.             temp2.transpose();
  289.             return temp2;
  290.        }
  291.        else {
  292.             //
  293.             // This is a curve, so we're done
  294.             //
  295.             return temp;
  296.        }
  297.     }
  298.  
  299.  
  300.     /**
  301.      * Refine this NURBS in the U direction by inserting new knots
  302.      * and control points.
  303.      * Refinement is done via recursive subdivision by adding
  304.      * segments new knots.
  305.      * @param uSegments the number of new control points
  306.      * @return the refined Nurbs
  307.      */
  308.     private Nurbs tessellateU(int uSegments) {
  309.         Nurbs temp    = new Nurbs();
  310.  
  311.         //
  312.         // First add new knots to U knot sequence
  313.         //
  314.         int uOrder    = this.getUOrder();
  315.         int numUKnots = Math.max(uSegments, this.getUOrder()*2 +1);
  316.         int numUControlPoints = numUKnots - this.getUOrder();
  317.  
  318.         temp.u = new Knot(uOrder, numUControlPoints);
  319.         temp.u.makeKnots(u.knot[0], u.knot[u.numKnots-1]);
  320.         temp.u = temp.u.unionKnots(this.u);
  321.  
  322.         //
  323.         // Copy the V knot sequence
  324.         //
  325.         temp.v        = (Knot) v.clone();
  326.  
  327. //      System.err.println("tessellate:  New U Knot Vector = " +
  328. //                                      temp.u.toString());
  329. //      System.err.println("tessellate:  New V Knot Vector = " +
  330. //                                      temp.v.toString());
  331.  
  332.         //
  333.         // Second create the new ControlNet
  334.         //
  335.         Point4[][] tmppoints = new Point4[temp.u.numControlPoints]
  336.                                          [temp.v.numControlPoints];
  337.         for (int i=0; i<temp.u.numControlPoints; i++) {
  338.             for (int j=0; j<temp.v.numControlPoints; j++) {
  339.                 // Creates the Point4 objects and initializes
  340.                 // them to zero
  341.                 tmppoints[i][j] = new Point4();
  342.             }
  343.         }
  344.         ControlNet tmpcontrol = new ControlNet(temp.u.numControlPoints,
  345.                                                temp.v.numControlPoints,
  346.                                                tmppoints);
  347.         temp.setControlNet(tmpcontrol);
  348.  
  349.         //
  350.         // Now refine in U direction
  351.         //
  352. //      System.err.println("loop over " + temp.u.numControlPoints);
  353.         //
  354.         // should this be over numKnots?  no, since
  355.         // numControlPoints = numKnots - order, and since we
  356.         // know that the last order knots are unchanged, we don't
  357.         // have to deal with those.
  358.         //
  359.         for (int i=0; i<temp.u.numControlPoints; i++) {
  360. //          System.err.println("in refine " + i);
  361.             // knotIndex tells us where this particular new knot lies
  362.             // in the old knot series
  363. //          System.err.println("new knot=" + temp.u.knot[i]);
  364.             int knotIndex = Knot.interval(this.u.knot, temp.u.knot[i]);
  365. //          System.err.println("Index knotIndex = " + knotIndex +
  366. //                             " out of " + getNumUKnots());
  367.             this.subdivide(temp, knotIndex, i);
  368.         }
  369.         return temp;
  370.     }
  371.  
  372.  
  373.     /**
  374.      * Calculates the control points corresponding to new knots.
  375.      * This is called once for each new knot and creates
  376.      * numVControlPoints new control points.
  377.      * @param temp the Nurbs which will contain the new control points
  378.      * @param oldKnotIndex  the index of the old knot
  379.      * @param newKnotIndex the index of the new knot
  380.      */
  381.     protected void subdivide(Nurbs temp, int oldKnotIndex, int newKnotIndex) {
  382.  
  383.         int ttsize = getUOrder();
  384.         Point4[][] tmppoints = new Point4[getUOrder()][oldKnotIndex+1];
  385.  
  386.         //
  387.         // Refine U
  388.         //
  389. //      System.err.println("subdivide:  kk loop over " + getNumVControlPoints());
  390.         for (int kk=0; kk<getNumVControlPoints(); kk++) {
  391. //          System.err.println("subdivide:  ii loop over mu=" +
  392. //                              oldKnotIndex + " nrb1.k=" + getUOrder());
  393.             for (int j=oldKnotIndex-getUOrder()+1; j<oldKnotIndex+1; j++) {
  394.                 tmppoints[0][j] = this.controlNet.controlPoints[j][kk];
  395. //              System.err.println("subdivide:  ttpts=" + tmppoints[0][j]);
  396.             }
  397.  
  398. //          System.err.println("subdivide:  ir loop over " + this.u.order);
  399.             for (int i=1; i<getUOrder(); i++) {
  400. //              System.err.println("subdivide:  ii(2) loop over mu=" +
  401. //                            oldKnotIndex + " nrb1.k=" + u.order + " ir=" + i);
  402.                 for (int j=oldKnotIndex-getUOrder()+1+i; j<oldKnotIndex+1; j++) {
  403.                     float t1 = temp.u.knot[newKnotIndex  + getUOrder() - i] -
  404.                                this.u.knot[j];
  405.                     float t2 = this.u.knot[j + getUOrder() - i] -
  406.                                temp.u.knot[newKnotIndex  + getUOrder() - i];
  407.                     float tmul = 1.0f / (t1 + t2);
  408. //                  System.err.println("subdivide:  t1=" + t1 +
  409. //                                     " t2=" + t2 + " tmul=" + tmul);
  410.                     // interpolate new control points using old
  411.                     // control points
  412. //                  System.err.println(" i = " + i + " j = " + j);
  413.                     tmppoints[i][j] = new Point4(
  414.                     (t1*tmppoints[i-1][j].x + t2*tmppoints[i-1][j-1].x) * tmul,
  415.                     (t1*tmppoints[i-1][j].y + t2*tmppoints[i-1][j-1].y) * tmul,
  416.                     (t1*tmppoints[i-1][j].z + t2*tmppoints[i-1][j-1].z) * tmul,
  417.                     (t1*tmppoints[i-1][j].w + t2*tmppoints[i-1][j-1].w) * tmul);
  418.                 }
  419.             }
  420. //          System.err.println("FINAL = " + tmppoints[getUOrder()-1][oldKnotIndex]);
  421.             temp.controlNet.controlPoints[newKnotIndex][kk] =
  422.                                 tmppoints[getUOrder()-1][oldKnotIndex];
  423.         }
  424.     }
  425.  
  426.  
  427.     /**
  428.      * Split this NURBS into two at the given location.
  429.      * @param dottedline the knot parameter at which to cut
  430.      * @return an array of two Nurbs objects
  431.      */
  432.     protected Nurbs[] split(float dottedline) {
  433.         //
  434.         // Not fully implemented yet
  435.  
  436.         //
  437.         // Find where in the knot sequence dottedline lies
  438.         //
  439.         int knotIndex = Knot.interval(u.knot, dottedline);
  440.         System.err.println("Index knotIndex = " + knotIndex +
  441.                            " out of " + getNumUKnots());
  442.  
  443.         //
  444.         // First create the Knots
  445.         //
  446.         int order = 0;
  447.         // need order more for the end of the sequence where the split is.
  448.         int numKnots = getNumUKnots() + getUOrder();
  449.         int numControlPoints = 0;
  450.  
  451.         //
  452.         // Copy first portion of knot sequence
  453.         //
  454.         float[] tmpknot = new float[numKnots];
  455.         for (int i=0; i<knotIndex; i++) {
  456.             tmpknot[i] = this.u.knot[i];
  457.         }
  458.  
  459.         int ir = getUOrder();
  460.         for (int i=0; i<getUOrder(); i++) {
  461.             if (dottedline == u.knot[knotIndex - i])
  462.                 ir--; 
  463.         }
  464.  
  465.         int iin = knotIndex;
  466.         for (int i=0; i<ir; i++) {
  467.             tmpknot[iin] = dottedline;
  468.             iin++;
  469.         }
  470.  
  471.         //
  472.         // Copy second portion of knot sequence
  473.         //
  474.         for (int i=knotIndex; i<getNumUKnots(); i++) {
  475.             tmpknot[i] = this.u.knot[i];
  476.         }
  477.  
  478.         Knot kk = new Knot(order, numControlPoints);
  479.         kk.setKnots(tmpknot);
  480.  
  481.         System.err.println("split:  Old U Knot Vector = " +
  482.                                     u.toString());
  483.         System.err.println("split:  New U Knot Vector = " +
  484.                                     kk.toString());
  485.  
  486. //OSLO
  487.         //
  488.         // Second create the new ControlNet
  489.         //
  490. Nurbs tmp = new Nurbs();
  491.         Point4[][] tmppoints = new Point4[tmp.u.numControlPoints]
  492.                                          [tmp.v.numControlPoints];
  493.         for (int i=0; i<tmp.u.numControlPoints; i++) {
  494.             for (int j=0; j<tmp.v.numControlPoints; j++) {
  495.                 // Creates the Point4 objects and initializes
  496.                 // them to zero
  497.                 tmppoints[i][j] = new Point4();
  498.             }
  499.         }
  500.         ControlNet tmpcontrol = new ControlNet(tmp.u.numControlPoints,
  501.                                                tmp.v.numControlPoints,
  502.                                                tmppoints);
  503.         tmp.setControlNet(tmpcontrol);
  504.  
  505.         //
  506.         // Now refine in U direction
  507.         //
  508.         // should this be over numKnots?  no, since
  509.         // numControlPoints = numKnots - order, and since we
  510.         // know that the last order knots are unchanged, we don't
  511.         // have to deal with those.
  512.         //
  513.         for (int i=0; i<tmp.u.numControlPoints; i++) {
  514.             // knotIndex tells us where this particular new knot lies
  515.             // in the old knot series
  516.             knotIndex = Knot.interval(this.u.knot, tmp.u.knot[i]);
  517.             this.subdivide(tmp, knotIndex, i);
  518.         }
  519.  
  520.        // blah blah
  521.  
  522.  
  523.         Nurbs[] temp = new Nurbs[2];
  524.         temp[0] = new Nurbs();
  525. //      temp[0] = new Nurbs(kk, (Knot) v.clone(), controlNet);
  526.         temp[1] = new Nurbs();
  527.  
  528.         return temp;
  529.     }
  530.  
  531.  
  532.     /**
  533.      * Perform a linear extrusion of this NURBS along the vector w
  534.      * to produce a new NURBS.  Leaves this instance unchanged.
  535.      * If this Nurbs instance is a surface, extrude the v.knot[0]
  536.      * curve only.
  537.      * @oaram w a vector for the extrusion.
  538.      * @return a Nurbs surface.
  539.      */
  540.     public Nurbs extrude(Point4 w) {
  541.         //
  542.         // Curve and Surface Construction using Rational B-splines
  543.         // Piegl and Tiller CAD Vol 19 #9 November 1987 pp 485-498
  544.         // 
  545.         int order            = 2;   // linear extrusion
  546.         int numControlPoints = 2;
  547.         int numKnots         = 4;
  548.  
  549.         //
  550.         // First create the Knots
  551.         //
  552.         float[] temp = new float[numKnots];
  553.         temp[0] = 0.0f;
  554.         temp[1] = 0.0f;
  555.         temp[2] = 1.0f;
  556.         temp[3] = 1.0f;
  557.  
  558.         Knot tmpVKnot = new Knot(order, numControlPoints);
  559.         tmpVKnot.setKnots(temp);
  560.  
  561.         //
  562.         // Second create the ControlNet
  563.         //
  564.         Point4[][] tmppoints = new Point4[u.numControlPoints]
  565.                                          [tmpVKnot.numControlPoints];
  566.         for (int i=0; i<u.numControlPoints; i++) {
  567.             for (int j=0; j<tmpVKnot.numControlPoints; j++) {
  568.                 // Creates the Point4 objects and initializes
  569.                 // them to zero
  570.                 tmppoints[i][j] = new Point4();
  571.             }
  572.         }
  573.  
  574.         for (int i=0; i<u.numControlPoints; i++) {
  575.             for (int j=0; j<tmpVKnot.numControlPoints; j++) {
  576.  
  577.                 /* Change added 11/02/90 Steve Larkin :
  578.                  * Have multiplied the term wcoord to the extrusion vector
  579.                  * before adding to the curve coordinates. Not really sure
  580.                  * this is the correct fix, but it works !
  581.                  */
  582.                 tmppoints[i][j].x = this.controlNet.controlPoints[i][0].x +
  583.                                     j*w.x;
  584.                 tmppoints[i][j].y = this.controlNet.controlPoints[i][0].y +
  585.                                     j*w.y;
  586.                 tmppoints[i][j].z = this.controlNet.controlPoints[i][0].z +
  587.                                     j*w.z;
  588.                 tmppoints[i][j].w = this.controlNet.controlPoints[i][0].w;
  589.             }
  590.         }
  591.         ControlNet tmpcontrol = new ControlNet(u.numControlPoints,
  592.                                                tmpVKnot.numControlPoints,
  593.                                                tmppoints);
  594.         return new Nurbs((Knot) u.clone(), tmpVKnot, tmpcontrol);
  595.     }
  596.  
  597.  
  598.     /**
  599.      * Do a surface of revolution about the Y axis.
  600.      * Assumes curve is in X-Y plane
  601.      * The profile NURBS will first be projected onto the Z=0 plane,
  602.      * the resulting projection will be revolved about the Y axis.
  603.      * Currently, thetamin and thetamax are ignored and 0, 2*PI is
  604.      * used in all cases.
  605.      * @param thetamin the angle at which to start the revolution
  606.      * @param thetamax the angle at which to end the revolution
  607.      * @return a Nurbs surface.
  608.      */
  609.     public Nurbs revolve(float thetamin, float thetamax) {
  610.         //
  611.         // Curve and Surface Construction using Rational B-splines
  612.         // Piegl and Tiller CAD Vol 19 #9 November 1987 pp 485-498
  613.         //
  614.         int order            =  3;
  615.         int numControlPoints =  9;
  616.         int numKnots         = 12;
  617.  
  618.         //
  619.         // First create the Knots for the circular cross section
  620.         // If we want to limit this to an arc , would be done here
  621.         // using the createArc() code rather than the createCircle()
  622.         // code.
  623.         //
  624.         float[] temp = { 0.00f, 0.00f, 0.00f,
  625.                          0.25f, 0.25f,
  626.                          0.50f, 0.50f,
  627.                          0.75f, 0.75f,
  628.                          1.00f, 1.00f, 1.00f };
  629.  
  630.         Knot tmpUKnot = new Knot(order, numControlPoints);
  631.         tmpUKnot.setKnots(temp);
  632.  
  633.         //
  634.         // Second create the ControlNet
  635.         //
  636.         Point4[][] tmppoints = new Point4[tmpUKnot.numControlPoints]
  637.                                          [u.numControlPoints];
  638.         for (int i=0; i<tmpUKnot.numControlPoints; i++) {
  639.             for (int j=0; j<u.numControlPoints; j++) {
  640.                 tmppoints[i][j] = new Point4();
  641.             }
  642.         }
  643.  
  644.         //
  645.         // Copy profile curve.
  646.         //
  647.         for (int i=0; i<u.numControlPoints; i++) {
  648.             tmppoints[0][i].x = controlNet.controlPoints[i][0].x;
  649.             tmppoints[0][i].y = controlNet.controlPoints[i][0].y;
  650.             tmppoints[0][i].z = 0.0f;            // Project onto Z=0 plane
  651.             tmppoints[0][i].w = controlNet.controlPoints[i][0].w;
  652.         }
  653.  
  654.         float ww = (float) Math.sqrt(2.0)/2.0f;
  655.  
  656.         //
  657.         // Sweep about Y axis.  The V direction will be
  658.         // a circle around the Y axis.
  659.         //
  660.         for (int i=0; i<u.numControlPoints; i++) {
  661.             for (int j=1; j<tmpUKnot.numControlPoints; j++) {
  662.                 tmppoints[j][i].y = tmppoints[0][i].y;
  663.             }
  664.  
  665.             float radius = tmppoints[0][i].x;
  666.             float weight = tmppoints[0][i].w;
  667.  
  668.             int jj = 1;
  669.             for (int j=0; j<4; j++) {
  670.                 tmppoints[jj  ][i].y *= ww;
  671.                 tmppoints[jj  ][i].w  = ww * weight;
  672.                 tmppoints[jj+1][i].w  = weight;
  673.                 jj += 2;
  674.             }
  675.  
  676.             tmppoints[1][i].x =  radius * ww;
  677.             tmppoints[1][i].z =  radius * ww;
  678.             tmppoints[7][i].x =  radius * ww;
  679.             tmppoints[7][i].z = -radius * ww;
  680.             tmppoints[2][i].x =  0.0f;
  681.             tmppoints[2][i].z =  radius;
  682.             tmppoints[6][i].x =  0.0f;
  683.             tmppoints[6][i].z = -radius;
  684.             tmppoints[3][i].x = -radius * ww;
  685.             tmppoints[3][i].z =  radius * ww;
  686.             tmppoints[5][i].x = -radius * ww;
  687.             tmppoints[5][i].z = -radius * ww;
  688.             tmppoints[4][i].x = -radius;
  689.             tmppoints[4][i].z =  0.0f;
  690.             tmppoints[8][i].x =  radius;
  691.             tmppoints[8][i].z =  0.0f;
  692.         }
  693.         ControlNet tmpcontrol = new ControlNet(tmpUKnot.numControlPoints,
  694.                                                u.numControlPoints,
  695.                                                tmppoints);
  696.         return new Nurbs(tmpUKnot, (Knot) u.clone(), tmpcontrol);
  697.     }
  698.  
  699.  
  700.     /**
  701.      * Increase the order of this NURBS
  702.      * @return the elevated Nurbs
  703.      */
  704.     public Nurbs elevate() {
  705.         //
  706.         // Not implemented yet
  707.         //
  708.         return new Nurbs();
  709.     }
  710.  
  711.  
  712.     /**
  713.      * Creates a String representation for the NURBS
  714.      * in the form of a VRML Coordinate node.
  715.      * @return a string representation of the Nurbs
  716.      */
  717.     public String toVRMLString() {
  718.         return controlNet.toVRMLString();
  719.     }
  720.  
  721.  
  722.     /**
  723.      * Creates a String representation for the NURBS
  724.      * in the form of a VRML Coordinate node.
  725.      * @return a string representation of the Nurbs
  726.      */
  727.     public String toVRMLCoordinateNode() {
  728.         return controlNet.toVRMLCoordinateNode();
  729.     }
  730.  
  731.  
  732.     /**
  733.      * Creates a String representation for the NURBS
  734.      * in the form of a VRML coordIndex field.
  735.      * @return a string representation of the Nurbs
  736.      */
  737.     public int[] toVRMLCoordIndex() {
  738.         return controlNet.toVRMLCoordIndex();
  739.     }
  740.  
  741.  
  742.     /**
  743.      * Creates a String representation for the NURBS
  744.      * @return a string representation of the Nurbs
  745.      */
  746.     public String toString() {
  747.         // Reserve enough space initially for a "typical" curve
  748.         // in order to minimize buffer resizing. 
  749.         StringBuffer buffer = new StringBuffer(1024);
  750.         buffer.append(getClass().getName() + ": ");
  751.         buffer.append("uOrder=" + getUOrder() + ", " +
  752.                       "vOrder=" + getVOrder() + "\n");
  753.         buffer.append("U Knot Sequence: " + u.toString() + "\n");
  754.         buffer.append("V Knot Sequence: " + v.toString() + "\n");
  755.         buffer.append("Control Points: "  + controlNet.toString());
  756.         return buffer.toString();
  757.     }
  758. }
  759.