001/*
002 *   Entity112_ParSplineCurve  -- An entity representing a Parametric Spline Curve Entity.
003 *
004 *   Copyright (C) 2013-2016, Joseph A. Huwaldt.
005 *   All rights reserved.
006 *   
007 *   part library is free software; you can redistribute it and/or
008 *   modify it under the terms of the GNU Lesser General Public
009 *   License as published by the Free Software Foundation; either
010 *   version 2.1 of the License, or (at your option) any later version.
011 *   
012 *   part library is distributed in the hope that it will be useful,
013 *   but WITHOUT ANY WARRANTY; without even the implied warranty of
014 *   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
015 *   Lesser General Public License for more details.
016 *
017 *   You should have received a copy of the GNU Lesser General Public License
018 *   along with part program; if not, write to the Free Software
019 *   Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.
020 *   Or visit:  http://www.gnu.org/licenses/lgpl.html
021 */
022package geomss.geom.reader.iges;
023
024import geomss.geom.GeomElement;
025import geomss.geom.Transformable;
026import geomss.geom.nurbs.BasicNurbsCurve;
027import geomss.geom.nurbs.ControlPoint;
028import geomss.geom.nurbs.KnotVector;
029import geomss.geom.nurbs.NurbsCurve;
030import java.io.IOException;
031import java.io.RandomAccessFile;
032import java.text.MessageFormat;
033import java.util.ArrayList;
034import java.util.List;
035import javax.measure.unit.Unit;
036import org.jscience.mathematics.vector.Float64Matrix;
037
038/**
039 * <b><i>PARAMETRIC SPLINE CURVE ENTITY</i></b> - This entity represents a Parametric
040 * Spline Curve that may be isolated or used as a component of a Composite Curve Entity or
041 * a Subfigure Entity. The parametric spline curve is a sequence of parametric polynomial
042 * segments.
043 * 
044 * <p>
045 * This entity, when read from an IGES file, is converted to a NURBS curve. This entity
046 * type can not be written out to an IGES file. The spline parameters are stored in the
047 * user data with the prefix "IGES_112_" followed by the parameter name.
048 * </p>
049 *
050 * <p> Modified by: Joseph A. Huwaldt </p>
051 * 
052 * @author Joseph A. Huwaldt, Date: March 9, 2013
053 * @version September 13, 2016
054 */
055public class Entity112_ParSplineCurve extends GeomSSEntity {
056
057    private int ctype = 3;          //  1=linear, 2=quadratic, 3=cubic, 4=Wilson-Fowler, 5=Modified Wilson-Fowler, 6=B-spline
058    private int H = 1;              //  Degree of continuity with respect to arc length
059    private int NDIM = 3;           //  Number of dimemsions (2=planar, 3=non-planar)
060    private int N = 1;              //  Number of segments
061    private double[] T = null;      //  Break points of piecewise polynomial
062    private double[][] A = null;    //  Polynomial in each direction for each segment
063    private double[][] B = null;
064    private double[][] C = null;
065    private double[][] D = null;
066    private double TP[][] = null;
067
068    private static final double[][] Bmat
069            =   {{1.,   0.,         0.,     0.},
070                {1.,    1. / 3.,    0.,     0.},
071                {1.,    2. / 3.,    1. / 3., 0.},
072                {1.,    1.,         1.,     1.}};
073    private static final Float64Matrix Bm = Float64Matrix.valueOf(Bmat);
074
075    private NurbsCurve curve;   //  The GeomSS curve this entity represents.
076
077    /**
078     * Default constructor.
079     *
080     * @param p  part to which this entity is contained
081     * @param de Directory Entry for this entity
082     */
083    public Entity112_ParSplineCurve(Part p, DirEntry de) {
084        super(p, de);
085
086        if (Constants.DEBUG) {
087            System.out.println("Entity112 constructor called");
088        }
089
090    }
091
092    /**
093     * Checks to see if the entity is correct. The following restrictions are imposed:
094     *
095     * - The Label Display Pointer shall be 0
096     */
097    @Override
098    public void check() {
099        DirEntry DE = getDirectoryEntry();
100
101        // DE LblDsp shall be 0
102        if (DE.getLblDsp() != 0) {
103            String msg = MessageFormat.format(RESOURCES.getString("labelDisplay"), DE.getLblDsp());
104            addErrorMessage(getWarningString(msg));
105        }
106
107    }
108
109    /**
110     * Read the Parameter Data from the String read in by the superclass.
111     *
112     * @param in input file
113     * @throws java.io.IOException
114     */
115    @Override
116    public void read(RandomAccessFile in) throws IOException {
117
118        if (Constants.DEBUG) {
119            System.out.println("Entity112.read() called");
120        }
121
122        super.read(in);
123        String s = getPDString();
124
125        if (Constants.DEBUG) {
126            System.out.println("PD String = \"" + s + "\"");
127        }
128
129        ctype = getInt(s);          //  Spline Type before conversion to Type 112
130        H = getInt(s);              //  Degree of continuity with respect to arc length
131        NDIM = getInt(s);           //  Number of dimensions
132        N = getInt(s);              //  Number of segments
133
134        //  Read in breakpoints of piecewise polynomial
135        T = new double[N + 1];        //  Allocate storage for the breakpoints
136        for (int i = 0; i <= N; ++i) {
137            double u = getReal(s);
138            T[i] = u;
139        }
140
141        //  Allocate memory for the polynomial segment coefficients.
142        A = new double[N][NDIM];
143        B = new double[N][NDIM];
144        C = new double[N][NDIM];
145        D = new double[N][NDIM];
146
147        //  Loop over each segment.
148        for (int i = 0; i < N; ++i) {
149            //  Read in the coefficients in each coordinate direction.
150            for (int j = 0; j < NDIM; ++j) {
151                A[i][j] = getReal(s);
152                B[i][j] = getReal(s);
153                C[i][j] = getReal(s);
154                D[i][j] = getReal(s);
155            }
156        }
157
158        //  Read in the remaining evaluation points.
159        TP = new double[NDIM][4];
160        for (int i = 0; i < NDIM; ++i) {
161            for (int j = 0; j < 4; ++j) {
162                TP[i][j] = getReal(s);
163            }
164        }
165
166        super.read_additional();
167    }
168
169    /**
170     * The GeomSS geometry element is created from the IGES parameters when this method is
171     * called.
172     */
173    @Override
174    void createGeometry() throws IOException {
175
176        //  Convert from polynomial coefficient form to B-Spline control points.
177        //      Reference:  Handbook of Grid Generation, Chapter 30, Section 30.3.0.
178        
179        //  Bezier control polygon: bmat[0..3] = Bm*Cmat
180        final int degree = 3;
181        final int order = degree + 1;
182        List<ControlPoint> cps = new ArrayList();
183        double[][] Cmat = new double[order][NDIM];
184        boolean firstPass = true;
185        for (int i = 0; i < N; ++i) {
186
187            //  Calculate the reparameterization factor.
188            double h = T[i + 1] - T[i];
189            double h2 = h * h;
190            double h3 = h2 * h;
191
192            //  Build up the polynomial coefficient matrix.
193            for (int j = 0; j < NDIM; ++j) {
194                Cmat[0][j] = A[i][j];
195                Cmat[1][j] = B[i][j] * h;
196                Cmat[2][j] = C[i][j] * h2;
197                Cmat[3][j] = D[i][j] * h3;
198            }
199
200            //  bmat = Bmat*Cmat
201            Float64Matrix Cm = Float64Matrix.valueOf(Cmat);
202            Float64Matrix bm = Bm.times(Cm);
203
204            //  Convert bm into a list of control points.
205            List<ControlPoint> cpList = cpMatrix2ControlPoints(bm, Constants.unit);
206            if (firstPass) {
207                //  Only add the 1st control point on the 1st segment.
208                firstPass = false;
209                cps.add(cpList.get(0));
210            }
211            for (int j = 1; j < order; ++j) {
212                cps.add(cpList.get(j));
213            }
214        }
215
216        //  Create a knot list and put a degree+1 touple knot at the start.
217        List<Double> knots = new ArrayList();
218        for (int i = 0; i <= degree; i++) {
219            knots.add(ZERO);
220        }
221
222        //  Add degree+1 touple knots where each Bezier segment is joined.
223        double ds = 1. / N;
224        double sv = 0;
225        for (int j = 1; j < N; ++j) {
226            sv += ds;
227            for (int i = 0; i < degree; i++) {
228                knots.add(sv);
229            }
230        }
231
232        //  Add a degree+1 touble set of knots at the end.
233        for (int i = 0; i <= degree; i++) {
234            knots.add(ONE);
235        }
236
237        //  Create the knot vector.
238        KnotVector kv = KnotVector.newInstance(degree, knots);
239
240        //  Create the curve.
241        curve = BasicNurbsCurve.newInstance(cps, kv);
242
243    }
244
245    /**
246     * Method used to apply IGES meta-data to GeomSS elements. This implementation stores
247     * in the user data, in addition to the header info, all the parameter information for
248     * this entity type prefixed by "IGES_112_".
249     */
250    @Override
251    protected void applyMetaData(GeomElement element) {
252        super.applyMetaData(element);
253        element.putUserData("IGES_112_CTYPE", ctype);
254        element.putUserData("IGES_112_H", H);
255        element.putUserData("IGES_112_N", N);
256        element.putUserData("IGES_112_T", T);
257        element.putUserData("IGES_112_A", A);
258        element.putUserData("IGES_112_B", B);
259        element.putUserData("IGES_112_C", C);
260        element.putUserData("IGES_112_D", D);
261        element.putUserData("IGES_112_TP", TP);
262        element.putUserData("IGES_U0", T[0]);
263        element.putUserData("IGES_U1", T[N]);
264    }
265
266    /**
267     * Return a list of control points from the input matrix of control point coordinates
268     * (points in rows, dimensions in columns).
269     *
270     */
271    private static List<ControlPoint> cpMatrix2ControlPoints(Float64Matrix Pmat, Unit units) {
272
273        //  Create a list of control points from the matrix of control point positions.
274        List<ControlPoint> cpList = new ArrayList();
275        int numPoints = Pmat.getNumberOfRows();
276        for (int i = 0; i < numPoints; i++) {
277            ControlPoint pnt = ControlPoint.valueOf(Pmat.getRow(i), 1., units);
278            cpList.add(pnt);
279        }
280
281        return cpList;
282    }
283
284    /**
285     * Return a reference to the Transformable GeomElement contained in this IGES Entity.
286     *
287     * @return A reference to the Transformable GeomElement contained in this IGES Entity.
288     */
289    @Override
290    protected Transformable getGeomElement() {
291        return curve;
292    }
293
294    /**
295     * Returns a short String describing this Entity object's type.
296     *
297     * @return A short String describing this Entity object's type.
298     */
299    @Override
300    public String getTypeString() {
301        return "Entity112 - Parametric Spline Curve";
302    }
303
304    /**
305     * Dump to String.
306     *
307     * @return String containing the resulting text.
308     */
309    @Override
310    public String toString() {
311        StringBuilder outStr = new StringBuilder(super.toString());
312        outStr.append("\n");
313
314        return outStr.toString();
315    }
316
317}