001/* 002 * Entity142_CurveOnSurface -- An entity representing a Curve On a Parametric Surface. 003 * 004 * Copyright (Ccrv) 2013-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.*; 024import geomss.geom.nurbs.BasicNurbsCurve; 025import geomss.geom.nurbs.ControlPoint; 026import geomss.geom.nurbs.CurveFactory; 027import geomss.geom.nurbs.NurbsCurve; 028import jahuwaldt.js.param.Parameter; 029import java.io.IOException; 030import java.io.PrintWriter; 031import java.io.RandomAccessFile; 032import java.util.List; 033import javax.measure.quantity.Length; 034import javax.measure.unit.SI; 035import javax.measure.unit.Unit; 036import javolution.context.StackContext; 037import javolution.util.FastTable; 038 039/** 040 * <b><i>CURVE ON A PARAMETRIC SURFACE ENTITY</i></b> - This entity represents a curve 041 * associated with a surface and identifies the curve as lying on the surface. 042 * 043 * <p> 044 * This entity, when read from an IGES file, is converted to a SubrangeCurve curve. This 045 * entity type can be written out to an IGES file. When reading in this entity, the IGES 046 * parameters are stored in the user data with the prefix "IGES_142_" followed by the 047 * parameter name. 048 * </p> 049 * 050 * <p> Modified by: Joseph A. Huwaldt </p> 051 * 052 * @author Joseph A. Huwaldt, Date: March 13, 2013 053 * @version April 10, 2016 054 */ 055public class Entity142_CurveOnSurface extends GeomSSEntity { 056 057 private int Crtn = 0; // Indicates the way the curve on the surface has been created: 058 // 0 = Unspecified, 1 = Projection of a givencurve on the surface, 059 // 2 = Intersection of two surfaces, 060 // 3 = Isoparametric curve, i.e., either a u- parametric or a v- parametric curve. 061 private int Sptr; // Pointer to the DE of the surface on which the curve lies 062 private int Bptr; // Pointer to the DE of the entity that contains the definition of 063 // the curve Bcrv in the parametric space (u, v) of the surface Ssrf 064 private int Cptr; // Pointer to the DE of the curve Ccrv 065 private int Pref = 1; // Indicates preferred representation in the sending system: 066 // 0 = Unspecified, 1 = S o B is preferred, 2 = C is preferred, 067 // 3 = C and S o B are equally preferred 068 069 private GeomList<SubrangeCurve> curves; // The list of GeomSS curves this entity represents. 070 071 /** 072 * Default constructor. 073 * 074 * @param p part to which this entity is contained 075 * @param de Directory Entry for this entity 076 */ 077 public Entity142_CurveOnSurface(Part p, DirEntry de) { 078 super(p, de); 079 080 if (Constants.DEBUG) { 081 System.out.println("Entity142 constructor called"); 082 } 083 084 } 085 086 /** 087 * Create this entity from the specified GeomSS geometry element. 088 * 089 * @param part The Part to which this entity is contained. 090 * @param DEnum The line count from the start of the Directory Entry Section for this 091 * entry (odd number). 092 * @param name The name to assign to the IGES entity or <code>nulL</code> for none. 093 * @param Sptr Pointer to the DE of the surface on which the curve lies. 094 * @param Bptr Pointer to the DE of the entity that contains the definition of the 095 * curve Bcrv in the parametric space (u, v) of the surface Ssrf 096 * @param Cptr Pointer to the DE of the curve Ccrv 097 */ 098 public Entity142_CurveOnSurface(Part part, int DEnum, String name, int Sptr, int Bptr, int Cptr) { 099 super(part, new DirEntry(142, 0, DEnum, 0, name)); 100 101 this.Sptr = Sptr; 102 this.Bptr = Bptr; 103 this.Cptr = Cptr; 104 105 } 106 107 /** 108 * Checks to see if the entity is correct. 109 */ 110 @Override 111 public void check() { } 112 113 /** 114 * Read the Parameter Data from the String read in by the superclass. 115 * 116 * @param in input file 117 * @throws java.io.IOException 118 */ 119 @Override 120 public void read(RandomAccessFile in) throws IOException { 121 122 if (Constants.DEBUG) { 123 System.out.println("Entity142.read() called"); 124 } 125 126 super.read(in); 127 String s = getPDString(); 128 129 if (Constants.DEBUG) { 130 System.out.println("PD String = \"" + s + "\""); 131 } 132 133 Crtn = getInt(s); // Indicates the way the curve on the surface has been created 134 Sptr = getInt(s); // Pointer to the DE of the surface on which the curve lies 135 Bptr = getInt(s); // Pointer to the DE of the entity that contains the definition of the curve Bcrv in the parametric space (u, v) of the surface Ssrf 136 Cptr = getInt(s); // Pointer to the DE of the curve Ccrv 137 Pref = getInt(s); // Indicates preferred representation in the sending system 138 139 super.read_additional(); 140 } 141 142 /** 143 * Method used to apply IGES meta-data to GeomSS elements. This implementation stores 144 * in the user data, in addition to the header info, all the parameter information for 145 * this entity type prefixed by "IGES_142_". 146 */ 147 @Override 148 protected void applyMetaData(GeomElement element) { 149 super.applyMetaData(element); 150 element.putUserData("IGES_142_CRTN", Crtn); 151 element.putUserData("IGES_142_PREF", Pref); 152 } 153 154 /** 155 * The GeomSS geometry element is created from the IGES parameters when this method is 156 * called. 157 */ 158 @Override 159 void createGeometry() throws IOException { 160 Part part = getPart(); 161 Parameter<Length> tol = Parameter.valueOf(Constants.Grain, Constants.unit); 162 curves = GeomList.newInstance(); 163 164 // Get the surface the curve is on. 165 Surface Ssrf; 166 Entity entity = part.getEntity(Sptr); 167 if (entity instanceof GeomSSEntity) { 168 GeomSSEntity geomEntity = (GeomSSEntity)entity; 169 geomEntity.setUsedInList(true); // Indicate that entity is used by this association. 170 Ssrf = (Surface)geomEntity.getGeomElement(GTransform.IDENTITY); 171 if (Ssrf == null) 172 return; 173 } else 174 return; 175 176 // Extract the original parametric bounds of the surface. 177 double sStart = (Double)Ssrf.getUserData("IGES_U0"); 178 double tStart = (Double)Ssrf.getUserData("IGES_V0"); 179 double sEnd = (Double)Ssrf.getUserData("IGES_U1"); 180 double tEnd = (Double)Ssrf.getUserData("IGES_V1"); 181 182 // Get the parametric space definition curve. 183 GeomList<NurbsCurve> Bcrvs = GeomList.newInstance(); 184 NurbsCurve Bcc; 185 entity = part.getEntity(Bptr); 186 if (entity instanceof GeomSSEntity) { 187 GeomSSEntity geomEntity = (GeomSSEntity)entity; 188 geomEntity.setUsedInList(true); // Indicate that the entity is used by this association. 189 Curve crv = (Curve)geomEntity.getGeomElement(GTransform.IDENTITY); 190 if (crv == null) 191 return; 192 193 // Convert the B curve to NURBS 194 Bcc = crv.toNurbs(tol); 195 196 // Change B units to METER to be consistant with the requirements of SubrangeCurve. 197 Bcc = changeCurveUnits(Bcc, SI.METER); 198 199 // Scale the B curve to the correct surface parametric range. 200 Bcc = scaleParCurve(sStart, sEnd, tStart, tEnd, Bcc); 201 202 // Convert B from 3D to 2D by dropping the Z dimension. 203 Bcc = Bcc.toDimension(2); 204 205 // Store the original B curve. 206 Bcc.putUserData("IGES_142_B", crv); 207 208 if (entity instanceof Entity102_CompositeCurve) { 209 // We have a composite B curve. We want the segments. 210 211 // Extract the segments of the composite curve. 212 GeomList<GeomElement> segs = (GeomList)crv.getUserData("IGES_102_CCSegs"); 213 curves.putUserData("IGES_142_BSegs", segs); 214 215 // Convert the segments to NurbsCurves 216 GeomList<NurbsCurve> crvSegs = convert2NurbsSegs(segs, tol); 217 218 // Convert all the segments to properly scaled subrange parameter curves. 219 for (NurbsCurve seg : crvSegs) { 220 // Change Bcrv units to METER to be consistant with the requirements of SubrangeCurve. 221 NurbsCurve nseg = changeCurveUnits(seg, SI.METER); 222 223 // Scale the B curve to the correct surface parametric range. 224 nseg = scaleParCurve(sStart, sEnd, tStart, tEnd, nseg); 225 226 // Convert B from 3D to 2D by dropping the Z dimension. 227 nseg = nseg.toDimension(2); 228 229 nseg.putUserData("IGES_142_BSeg", seg); 230 231 // Save the segment in the Bcrvs list. 232 Bcrvs.add(nseg); 233 } 234 235 } else { 236 // Just a single curve segment. 237 Bcrvs.add(Bcc); 238 Bcc = null; 239 } 240 241 } else 242 return; 243 244 // Get the model space curve coincident with the curve on the surface. 245 Curve Ccrv = null; 246 entity = part.getEntity(Cptr); 247 if (entity instanceof GeomSSEntity) { 248 GeomSSEntity geomEntity = (GeomSSEntity)entity; 249 geomEntity.setUsedInList(true); // Indicate that the entity is used by this association. 250 Ccrv = (Curve)geomEntity.getGeomElement(GTransform.IDENTITY); 251 } 252 253 // Create the curves. 254 for (NurbsCurve B : Bcrvs) { 255 SubrangeCurve curve = SubrangeCurve.newInstance(Ssrf, B); 256 if (Ccrv != null) 257 curve.putUserData("IGES_142_C", Ccrv); 258 curves.add(curve); 259 } 260 if (Ccrv != null) 261 curves.putUserData("IGES_142_C", Ccrv); 262 if (Bcc != null) 263 // This will only be added if B was originally a composite curve. 264 curves.putUserData("IGES_142_Bcc", Bcc); 265 } 266 267 /** 268 * Converts all the non-degenerate Curve elements in the specified geometry list into 269 * NurbsCurves. 270 * 271 * @param crvs The list of geometry elements to be converted. 272 * @param tol The tolerance for the conversion to NURBS curves. 273 * @return A list of non-degenerate NURBS curve versions of each element in "crvs". 274 */ 275 private static GeomList<NurbsCurve> convert2NurbsSegs(GeomList<GeomElement> crvs, Parameter<Length> tol) { 276 GeomList<NurbsCurve> nurbsSegs = GeomList.newInstance(); 277 for (GeomElement elem : crvs) { 278 if (elem instanceof Curve) { 279 NurbsCurve nurbs = ((Curve)elem).toNurbs(tol); 280 nurbsSegs.add(nurbs); 281 } else if (elem instanceof GeomPoint) { 282 NurbsCurve nurbs = CurveFactory.createPoint(1, (GeomPoint)elem); 283 nurbsSegs.add(nurbs); 284 } 285 } 286 return nurbsSegs; 287 } 288 289 /** 290 * Return a new curve with the same numerical values as the 1st curve, but with the 291 * units changed to those specified. 292 * 293 * @param crv The curve to have the units changed. 294 * @param unit The new unit for the output curve. 295 * @return A curve with the same numerical values as the "crv", but with the units 296 * changed to "unit". 297 */ 298 private static NurbsCurve changeCurveUnits(NurbsCurve crv, Unit<Length> unit) { 299 StackContext.enter(); 300 try { 301 302 List<ControlPoint> oldCPList = crv.getControlPoints(); 303 FastTable<ControlPoint> newCPList = FastTable.newInstance(); 304 for (ControlPoint cp : oldCPList) { 305 Point p = cp.getPoint(); 306 double w = cp.getWeight(); 307 Point pnew = Point.valueOf(p.getValue(0), p.getValue(1), 0, unit); 308 newCPList.add(ControlPoint.valueOf(pnew, w)); 309 } 310 crv = BasicNurbsCurve.newInstance(newCPList, crv.getKnotVector()); 311 return StackContext.outerCopy((BasicNurbsCurve)crv); 312 313 } finally { 314 StackContext.exit(); 315 } 316 } 317 318 /** 319 * Scales an input parametric curve who's values range from sStart,tStart to sEnd,tEnd 320 * to a new curve who's values range from 0,0 to 1,1. 321 * 322 * @param sStart The parametric S starting position on the parent surface. 323 * @param sEnd The parametric T starting position on the parent surface. 324 * @param tStart The parametric S ending position on the parent surface. 325 * @param tEnd The parametric T ending position on the parent surface. 326 * @param crv The curve, in the range, sStart,tStart to sEnd,tEnd to be scaled. 327 * @return A new curve that is scaled off the input curve that is in the range 0,0 to 328 * 1,1. 329 */ 330 private static NurbsCurve scaleParCurve(double sStart, double sEnd, double tStart, double tEnd, NurbsCurve crv) { 331 double mS = 1. / (sEnd - sStart); 332 double mT = 1. / (tEnd - tStart); 333 GTransform Tt = GTransform.newTranslation(-sStart, -tStart, 0); // Translate sStart,tStart to 0,0. 334 GTransform Ts = GTransform.valueOf(mS, mT, 1, 1); // Scale S & T to the right range. 335 GTransform T = Ts.times(Tt); 336 crv = crv.getTransformed(T).copyToReal(); 337 338 // Are there small round-off errors causing the parameters to be out of bounds? 339 final double tol = 1e-4; 340 double min = crv.getLimitPoint(0, false, tol/10).getValue(0); 341 double max = crv.getLimitPoint(0, true, tol/10).getValue(0); 342 if (min < -tol || max > 1 + tol) 343 throw new IllegalArgumentException("Parametric curve out of range in Entity142: u0 = " + min + ", u1 = " + max); 344 sStart = 0; 345 sEnd = 1; 346 if (min < 0) 347 sStart = min; 348 if (max > 1) 349 sEnd = max; 350 mS = 1. / (sEnd - sStart); 351 352 min = crv.getLimitPoint(1, false, tol/10).getValue(1); 353 max = crv.getLimitPoint(1, true, tol/10).getValue(1); 354 if (min < -tol || max > 1 + tol) 355 throw new IllegalArgumentException("Parametric curve out of range in Entity142: v0 = " + min + ", v1 = " + max); 356 tStart = 0; 357 tEnd = 1; 358 if (min < 0) 359 tStart = min; 360 if (max > 1) 361 tEnd = max; 362 mT = 1. / (tEnd - tStart); 363 if (mS != 1 || mT != 1) { 364 Tt = GTransform.newTranslation(-sStart, -tStart, 0); 365 Ts = GTransform.valueOf(mS, mT, 1, 1); 366 T = Ts.times(Tt); 367 crv = crv.getTransformed(T).copyToReal(); 368 } 369 370 return crv; 371 } 372 373 /** 374 * Return a reference to the Transformable GeomElement contained in this IGES Entity. 375 * 376 * @return A reference to the Transformable GeomElement contained in this IGES Entity. 377 */ 378 @Override 379 protected Transformable getGeomElement() { 380 if (curves.size() == 1) 381 return curves.get(0); 382 return curves; 383 } 384 385 /** 386 * Returns <code>true</code> if the Entity can be written to an exchange file. 387 * 388 * @return true 389 */ 390 @Override 391 public boolean canWrite() { 392 return true; 393 } 394 395 /** 396 * Write this entity object's parameter data to the specified PrintWriter. 397 * 398 * @param writer The PrintWriter to write the parameter data for this entity to. 399 * @param PDnum The starting Parameter Data row index number. 400 * @return The Parameter Data row index number for the next row. 401 * @throws java.io.IOException 402 */ 403 @Override 404 public int write(PrintWriter writer, int PDnum) throws IOException { 405 // Build up the parameter data string. 406 StringBuilder buffer = new StringBuilder(); 407 buffer.append(142); buffer.append(Constants.Delim); 408 buffer.append(Crtn); buffer.append(Constants.Delim); 409 buffer.append(Sptr); buffer.append(Constants.Delim); 410 buffer.append(Bptr); buffer.append(Constants.Delim); 411 buffer.append(Cptr); buffer.append(Constants.Delim); 412 buffer.append(Pref); buffer.append(Constants.Term); 413 414 // Write it out. 415 int oldPDnum = PDnum; 416 PDnum = Constants.writeSection(writer, PDnum, Constants.makeSequenceNumber(getDENum()), 417 'P', buffer); 418 419 // Store the PD line number and line count in the directory entry. 420 getDirectoryEntry().setPDNumber(oldPDnum, PDnum - oldPDnum); 421 422 return PDnum; 423 } 424 425 /** 426 * Returns a short String describing this Entity object's type. 427 * 428 * @return A short String describing this Entity object's type. 429 */ 430 @Override 431 public String getTypeString() { 432 return "Entity142 - Curve on Parametric Surface"; 433 } 434 435 /** 436 * Dump to String. 437 * 438 * @return String containing the resulting text. 439 */ 440 @Override 441 public String toString() { 442 StringBuilder outStr = new StringBuilder(super.toString()); 443 outStr.append("\n"); 444 445 outStr.append("Crtn = "); outStr.append(Crtn); outStr.append("\n"); 446 outStr.append("Sptr = "); outStr.append(Sptr); outStr.append("\n"); 447 outStr.append("Bptr = "); outStr.append(Sptr); outStr.append("\n"); 448 outStr.append("Cptr = "); outStr.append(Sptr); outStr.append("\n"); 449 outStr.append("Pref = "); outStr.append(Sptr); outStr.append("\n"); 450 451 return outStr.toString(); 452 } 453}