001/* 002 * Entity128_BSplineSurface -- An entity representing a Rational B-Spline Surface. 003 * 004 * Copyright (C) 2010-2016, 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.Point; 025import geomss.geom.Transformable; 026import geomss.geom.nurbs.*; 027import jahuwaldt.tools.math.MathTools; 028import java.io.IOException; 029import java.io.PrintWriter; 030import java.io.RandomAccessFile; 031import java.text.MessageFormat; 032import java.util.List; 033 034/** 035 * <p> 036 * <b><i>RATIONAL B-SPLINE SURFACE ENTITY</i></b> - This entity represents a Rational 037 * B-Spline Surface. This represents a parametric equation obtained by dividing two 038 * summations involving weights (which are real numbers), the control points, and B-Spline 039 * basis functions.</p> 040 * 041 * <p> 042 * This entity, when read from an IGES file, is converted to a NURBS surface. This entity 043 * type <b>can</b> be written out to an IGES file. When reading in this entity, all IGES 044 * parameters are stored in the user data with the prefix "IGES_128_" followed by the 045 * parameter name. 046 * </p> 047 * 048 * <p> Modified by: Joseph A. Huwaldt </p> 049 * 050 * @author Joseph A. Huwaldt, Date: August 23, 2010 051 * @version April 7, 2016 052 */ 053public class Entity128_BSplineSurface extends GeomSSEntity { 054 055 private int prop1 = 0; // 0=closed in S-direction, 1=not closed 056 private int prop2 = 0; // 0=closed in T-direction, 1=not closed 057 private int prop3 = 0; // 0=rational, 1=polynomial 058 private int prop4 = 0; // 0=non-periodic (clamped) in S-direction, 1=periodic (un-clamped). 059 private int prop5 = 0; // 0=non-periodic (clamped) in T-direction, 1=periodic (un-clamped). 060 private double[] sKnots = null; // Knot sequence in S-direction 061 private double[] tKnots = null; // Knot sequence in T-direction 062 private double uSstart = 0;// Starting parameter value in S-direction. 063 private double uSend = 1; // Ending parameter value in S-direction. 064 private double uTstart = 0;// Starting parameter value in T-direction. 065 private double uTend = 1; // Ending parameter value in T-direction. 066 067 private NurbsSurface surface; // The GeomSS surface this entity represents. 068 069 /** 070 * Default constructor. 071 * 072 * @param p part to which this entity is contained 073 * @param de Directory Entry for this entity 074 */ 075 public Entity128_BSplineSurface(Part p, DirEntry de) { 076 super(p, de); 077 078 if (Constants.DEBUG) { 079 System.out.println("Entity128 constructor called"); 080 } 081 082 } 083 084 /** 085 * Create this entity from the specified GeomSS geometry element. 086 * 087 * @param part The Part in which this entity is contained. 088 * @param DEnum The line count from the start of the Directory Entry Section for this 089 * entry (odd number). 090 * @param geom The GeomSS geometry to return an Entity for. 091 */ 092 public Entity128_BSplineSurface(Part part, int DEnum, NurbsSurface geom) { 093 super(part, new DirEntry(128, 0, DEnum, 0, geom.getName())); 094 surface = geom; 095 096 // Is the surface closed in S-direction? 097 prop1 = 1; 098 int numCols = surface.getNumberOfColumns(); 099 for (int i = 0; i < numCols; ++i) { 100 NurbsCurve curve = surface.getSCurve(i); 101 if (!curve.getRealPoint(0).distance(curve.getRealPoint(1)).isApproxZero()) { 102 prop1 = 0; 103 break; 104 } 105 } 106 107 // Is the surface closed in T-direction? 108 prop2 = 1; 109 int numRows = surface.getNumberOfRows(); 110 for (int i = 0; i < numRows; ++i) { 111 NurbsCurve curve = surface.getTCurve(i); 112 if (!curve.getRealPoint(0).distance(curve.getRealPoint(1)).isApproxZero()) { 113 prop2 = 0; 114 break; 115 } 116 } 117 118 // Is the surface rational (prop3 = 0) or polynomial (prop3 = 1)? 119 ControlPointNet cpNet = surface.getControlPoints(); 120 double w = cpNet.get(0, 0).getWeight(); 121 prop3 = 1; 122 for (List<ControlPoint> column : cpNet) { 123 for (ControlPoint cp : column) { 124 if (Math.abs(cp.getWeight() - w) > MathTools.EPS) { 125 prop3 = 0; 126 break; 127 } 128 } 129 } 130 131 // Store the knot vectors of this surface. 132 int K1 = cpNet.getNumberOfRows() - 1; 133 int K2 = cpNet.getNumberOfColumns() - 1; 134 KnotVector kv = surface.getSKnotVector(); 135 int M1 = kv.getDegree(); 136 int n = kv.length(); 137 sKnots = new double[n]; 138 for (int i = 0; i < n; ++i) 139 sKnots[i] = kv.getValue(i); 140 141 kv = surface.getTKnotVector(); 142 int M2 = kv.getDegree(); 143 n = kv.length(); 144 tKnots = new double[n]; 145 for (int i = 0; i < n; ++i) 146 tKnots[i] = kv.getValue(i); 147 148 } 149 150 /** 151 * Checks to see if the entity is correct. The following restrictions are imposed: 152 * 153 * - The Label Display Pointer shall be 0 154 */ 155 @Override 156 public void check() { 157 DirEntry DE = getDirectoryEntry(); 158 159 // DE LblDsp shall be 0 160 if (DE.getLblDsp() != 0) { 161 String msg = MessageFormat.format(RESOURCES.getString("labelDisplay"), DE.getLblDsp()); 162 addErrorMessage(getWarningString(msg)); 163 } 164 165 } 166 167 /** 168 * Read the Parameter Data from the String read in by the superclass. 169 * 170 * @param in input file 171 * @throws java.io.IOException 172 */ 173 @Override 174 public void read(RandomAccessFile in) throws IOException { 175 176 if (Constants.DEBUG) 177 System.out.println("Entity128.read() called for " + getHeader()); 178 179 super.read(in); 180 String s = getPDString(); 181 182 if (Constants.DEBUG) 183 System.out.println("PD String = \"" + s + "\""); 184 185 int K1 = getInt(s); // Number of control points. 186 int K2 = getInt(s); // Number of control points. 187 int M1 = getInt(s); // Degree of basis functions. 188 int M2 = getInt(s); // Degree of basis functions. 189 prop1 = getInt(s); 190 prop2 = getInt(s); 191 prop3 = getInt(s); 192 prop4 = getInt(s); 193 prop5 = getInt(s); 194 195 int n = K1 + 1 + M1 + 1; // Number of knots. 196 sKnots = new double[n]; 197 for (int i = 0; i < n; ++i) { 198 double u = getReal(s); 199 sKnots[i] = u; 200 } 201 202 n = K2 + 1 + M2 + 1; // Number of knots. 203 tKnots = new double[n]; 204 for (int i = 0; i < n; ++i) { 205 double u = getReal(s); 206 tKnots[i] = u; 207 } 208 209 double[][] weights = new double[K2 + 1][K1 + 1]; 210 for (int i = 0; i <= K2; ++i) { 211 for (int j = 0; j <= K1; ++j) { 212 double w = getReal(s); 213 weights[i][j] = w; 214 } 215 } 216 217 Point[][] cps = new Point[K2 + 1][K1 + 1]; 218 for (int i = 0; i <= K2; ++i) { 219 for (int j = 0; j <= K1; ++j) { 220 cps[i][j] = getPoint3(s); 221 } 222 } 223 224 uSstart = getReal(s); 225 uSend = getReal(s); 226 uTstart = getReal(s); 227 uTend = getReal(s); 228 229 // Make sure all the knots read in are in-range. 230 n = sKnots.length; 231 for (int i = 0; i < n; ++i) { 232 double kv = sKnots[i]; 233 if (kv < uSstart) 234 sKnots[i] = uSstart; 235 else if (kv > uSend) 236 sKnots[i] = uSend; 237 } 238 n = tKnots.length; 239 for (int i = 0; i < n; ++i) { 240 double kv = tKnots[i]; 241 if (kv < uTstart) 242 tKnots[i] = uTstart; 243 else if (kv > uTend) 244 tKnots[i] = uTend; 245 } 246 247 // Scale the knots into the range 0-1. 248 double[] scaledSKnots = sKnots; 249 if (Math.abs(uSstart) > MathTools.EPS || Math.abs(uSend - 1.0) > MathTools.EPS) { 250 n = sKnots.length; 251 scaledSKnots = new double[n]; 252 double m = 1. / (uSend - uSstart); 253 double b = -m * uSstart; 254 for (int i = 0; i < n; ++i) { 255 double kv = sKnots[i]; 256 kv = scaleKnot(m, b, kv); 257 scaledSKnots[i] = kv; 258 } 259 } 260 double[] scaledTKnots = tKnots; 261 if (Math.abs(uTstart) > MathTools.EPS || Math.abs(uTend - 1.0) > MathTools.EPS) { 262 n = tKnots.length; 263 scaledTKnots = new double[n]; 264 double m = 1. / (uTend - uTstart); 265 double b = -m * uTstart; 266 for (int i = 0; i < n; ++i) { 267 double kv = tKnots[i]; 268 kv = scaleKnot(m, b, kv); 269 scaledTKnots[i] = kv; 270 } 271 } 272 273 // Create the knot vector. 274 KnotVector kvS = KnotVector.newInstance(M1, scaledSKnots); 275 KnotVector kvT = KnotVector.newInstance(M2, scaledTKnots); 276 277 // Create the control point network. 278 ControlPoint[][] controlPoints = new ControlPoint[K2 + 1][K1 + 1]; 279 for (int i = 0; i <= K2; ++i) { 280 for (int j = 0; j <= K1; ++j) { 281 double weight = weights[i][j]; 282 Point pnt = cps[i][j]; 283 controlPoints[i][j] = ControlPoint.valueOf(pnt, weight); 284 } 285 } 286 ControlPointNet cpNet = ControlPointNet.valueOf(controlPoints); 287 288 // Create the surface. 289 surface = BasicNurbsSurface.newInstance(cpNet, kvS, kvT); 290 291 super.read_additional(); 292 } 293 294 /** 295 * Method used to apply IGES meta-data to GeomSS elements. This implementation stores 296 * in the user data, in addition to the header info, all the parameter information for 297 * this entity type prefixed by "IGES_128_". The range of original U,V parameter 298 * values is also avaliable as "IGES_U0", "IGES_U1", etc. 299 */ 300 @Override 301 protected void applyMetaData(GeomElement element) { 302 super.applyMetaData(element); 303 element.putUserData("IGES_128_PROP1", prop1); 304 element.putUserData("IGES_128_PROP2", prop2); 305 element.putUserData("IGES_128_PROP3", prop3); 306 element.putUserData("IGES_128_PROP4", prop4); 307 element.putUserData("IGES_128_PROP5", prop5); 308 element.putUserData("IGES_U0", uSstart); 309 element.putUserData("IGES_U1", uSend); 310 element.putUserData("IGES_V0", uTstart); 311 element.putUserData("IGES_V1", uTend); 312 } 313 314 /** 315 * The GeomSS geometry element is created from the IGES parameters when this method is 316 * called. 317 */ 318 @Override 319 void createGeometry() throws IOException { 320 // Everything was done in "read()". 321 } 322 323 /** 324 * Scale the knot value in the the required range from 0.0 to 1.0. 325 */ 326 private double scaleKnot(double m, double b, double value) { 327 // Scale the knot value. 328 double kv = m * value + b; 329 330 // Watch for roundoff. 331 if (kv < 0.0) 332 kv = 0.0; 333 else if (kv > 1.0) 334 kv = 1.0; 335 336 return kv; 337 } 338 339 /** 340 * Return a reference to the Transformable GeomElement contained in this IGES Entity. 341 * 342 * @return A reference to the Transformable GeomElement contained in this IGES Entity. 343 */ 344 @Override 345 protected Transformable getGeomElement() { 346 return surface; 347 } 348 349 /** 350 * Returns <code>true</code> if the Entity can be written to an exchange file. 351 * 352 * @return true 353 */ 354 @Override 355 public boolean canWrite() { 356 return true; 357 } 358 359 /** 360 * Write this entities parameter data to the specified PrintWriter. 361 * 362 * @param writer The PrintWriter to write the parameter data for this entity to. 363 * @param PDnum The starting Parameter Data row index number. 364 * @return The Parameter Data row index number for the next row. 365 * @throws java.io.IOException 366 */ 367 @Override 368 public int write(PrintWriter writer, int PDnum) throws IOException { 369 370 // Build up the parameter data string. 371 NurbsSurface srf = surface.to(Constants.unit); 372 ControlPointNet cpNet = srf.getControlPoints(); 373 int K1 = cpNet.getNumberOfRows() - 1; 374 int K2 = cpNet.getNumberOfColumns() - 1; 375 KnotVector sKV = srf.getSKnotVector(); 376 KnotVector tKV = srf.getTKnotVector(); 377 int M1 = sKV.getDegree(); 378 int M2 = tKV.getDegree(); 379 380 StringBuilder buffer = new StringBuilder(); 381 buffer.append(128); buffer.append(Constants.Delim); 382 buffer.append(K1); buffer.append(Constants.Delim); 383 buffer.append(K2); buffer.append(Constants.Delim); 384 buffer.append(M1); buffer.append(Constants.Delim); 385 buffer.append(M2); buffer.append(Constants.Delim); 386 buffer.append(prop1); buffer.append(Constants.Delim); 387 buffer.append(prop2); buffer.append(Constants.Delim); 388 buffer.append(prop3); buffer.append(Constants.Delim); 389 buffer.append(prop4); buffer.append(Constants.Delim); 390 buffer.append(prop5); buffer.append(Constants.Delim); 391 392 int n = sKV.length(); 393 for (int i = 0; i < n; ++i) { 394 double u = sKV.getValue(i); 395 buffer.append(u); 396 buffer.append(Constants.Delim); 397 } 398 399 n = tKV.length(); 400 for (int i = 0; i < n; ++i) { 401 double u = tKV.getValue(i); 402 buffer.append(u); 403 buffer.append(Constants.Delim); 404 } 405 406 for (int i = 0; i <= K2; ++i) { 407 for (int j = 0; j <= K1; ++j) { 408 double w = cpNet.get(j, i).getWeight(); 409 buffer.append(w); 410 buffer.append(Constants.Delim); 411 } 412 } 413 414 for (int i = 0; i <= K2; ++i) { 415 for (int j = 0; j <= K1; ++j) { 416 Point cp = cpNet.get(j, i).getPoint(); 417 appendPoint3(buffer, cp); 418 } 419 } 420 421 buffer.append(uSstart); buffer.append(Constants.Delim); 422 buffer.append(uSend); buffer.append(Constants.Delim); 423 buffer.append(uTstart); buffer.append(Constants.Delim); 424 buffer.append(uTend); buffer.append(Constants.Term); 425 426 // Write it out. 427 int oldPDnum = PDnum; 428 PDnum = Constants.writeSection(writer, PDnum, Constants.makeSequenceNumber(getDENum()), 429 'P', buffer); 430 431 // Store the PD line number and line count in the directory entry. 432 getDirectoryEntry().setPDNumber(oldPDnum, PDnum - oldPDnum); 433 434 return PDnum; 435 } 436 437 /** 438 * Returns a short String describing this Entity object's type. 439 * 440 * @return A short String describing this Entity object's type. 441 */ 442 @Override 443 public String getTypeString() { 444 return "Entity128 - Rational B-Spline Surface"; 445 } 446 447 /** 448 * Dump to String. 449 * 450 * @return String containing the resulting text. 451 */ 452 @Override 453 public String toString() { 454 if (surface == null) 455 return super.toString(); 456 457 StringBuilder outStr = new StringBuilder(super.toString()); 458 outStr.append("\n"); 459 460 ControlPointNet cpNet = surface.getControlPoints(); 461 int K1 = cpNet.getNumberOfRows()-1; 462 int K2 = cpNet.getNumberOfColumns()-1; 463 int M1 = surface.getSDegree(); 464 int M2 = surface.getTDegree(); 465 466 outStr.append("K1 = "); outStr.append(K1); outStr.append("\n"); 467 outStr.append("K2 = "); outStr.append(K2); outStr.append("\n"); 468 outStr.append("M1 = "); outStr.append(M1); outStr.append("\n"); 469 outStr.append("M2 = "); outStr.append(M2); outStr.append("\n"); 470 outStr.append("prop1 = "); outStr.append(prop1); outStr.append("\n"); 471 outStr.append("prop2 = "); outStr.append(prop2); outStr.append("\n"); 472 outStr.append("prop3 = "); outStr.append(prop3); outStr.append("\n"); 473 outStr.append("prop4 = "); outStr.append(prop4); outStr.append("\n"); 474 outStr.append("prop5 = "); outStr.append(prop5); outStr.append("\n"); 475 476 int n = sKnots.length; 477 for (int i = 0; i < n; i++) { 478 outStr.append("S("); outStr.append(i); outStr.append("): "); 479 outStr.append(sKnots[i]); outStr.append("\n"); 480 } 481 outStr.append("\n"); 482 483 n = tKnots.length; 484 for (int i = 0; i < n; i++) { 485 outStr.append("T("); outStr.append(i); outStr.append("): "); 486 outStr.append(tKnots[i]); outStr.append("\n"); 487 } 488 outStr.append("\n"); 489 490 for (int i=0; i <= K2; i++) { 491 for (int j=0; j <= K1; j++) { 492 double weight = cpNet.get(j,i).getWeight(); 493 outStr.append("W("); outStr.append(j); outStr.append(","); 494 outStr.append(i); outStr.append("): "); 495 outStr.append(weight); outStr.append("\n"); 496 } 497 } 498 499 for (int i=0; i <= K2; i++) { 500 for (int j=0; j <= K1; j++) { 501 Point pnt = cpNet.get(j,i).getPoint(); 502 outStr.append("X("); outStr.append(j); outStr.append(","); 503 outStr.append(i); outStr.append("): "); 504 outStr.append(pnt.get(0)); outStr.append("\n"); 505 outStr.append("Y("); outStr.append(j); outStr.append(","); 506 outStr.append(i); outStr.append("): "); 507 outStr.append(pnt.get(1)); outStr.append("\n"); 508 outStr.append("Z("); outStr.append(j); outStr.append(","); 509 outStr.append(i); outStr.append("): "); 510 outStr.append(pnt.get(2)); outStr.append("\n"); 511 } 512 } 513 514 outStr.append("uSstart = "); outStr.append(uSstart); outStr.append("\n"); 515 outStr.append("uSend = "); outStr.append(uSend); outStr.append("\n"); 516 outStr.append("uTstart = "); outStr.append(uTstart); outStr.append("\n"); 517 outStr.append("uTend = "); outStr.append(uTend); outStr.append("\n"); 518 519 return outStr.toString(); 520 } 521 522}