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