001/* 002 * IGESGeomReader -- A class that can read and write an IGES formatted geometry file. 003 * 004 * Copyright (C) 2010-2016, Joseph A. Huwaldt 005 * All rights reserved. 006 * 007 * This 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 * This 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 this 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; 023 024import geomss.geom.*; 025import geomss.geom.nurbs.BasicNurbsCurve; 026import geomss.geom.nurbs.ControlPoint; 027import geomss.geom.nurbs.CurveUtils; 028import geomss.geom.nurbs.NurbsCurve; 029import geomss.geom.reader.iges.*; 030import jahuwaldt.js.param.Parameter; 031import java.io.File; 032import java.io.IOException; 033import java.io.PrintWriter; 034import java.io.RandomAccessFile; 035import java.nio.charset.StandardCharsets; 036import java.text.MessageFormat; 037import java.util.List; 038import java.util.Locale; 039import static java.util.Objects.isNull; 040import static java.util.Objects.nonNull; 041import static java.util.Objects.requireNonNull; 042import javax.measure.quantity.Length; 043import javax.measure.unit.SI; 044import javax.measure.unit.Unit; 045import javolution.context.StackContext; 046import javolution.util.FastMap; 047import javolution.util.FastTable; 048 049/** 050 * A {@link GeomReader} for reading and writing geometry to an IGES 051 * formatted transfer file. This implementation ignores many the IGES entity types at this 052 * time. 053 * 054 * <p> Modified by: Joseph A. Huwaldt </p> 055 * 056 * @author Joseph A. Huwaldt, Date: August 21, 2010 057 * @version September 9, 2016 058 */ 059public class IGESGeomReader extends AbstractGeomReader { 060 061 // A brief description of the data read by this reaader. 062 private static final String DESCRIPTION = RESOURCES.getString("igesDescription"); 063 064 // The preferred file extension for files of this reader's type. 065 public static final String EXTENSION = "igs"; 066 067 /** 068 * A mapping of IGES Entity objects to geometry elements. This is used to prevent 069 * multiple instances of the same element being written to an IGES transfer. 070 */ 071 private FastMap<GeomElement, Entity> elementEntityMap; 072 073 /** 074 * Returns a string representation of the object. This will return a brief description 075 * of the format read by this reader. 076 * 077 * @return A brief description of the format read by this reader. 078 */ 079 @Override 080 public String toString() { 081 return DESCRIPTION; 082 } 083 084 /** 085 * Returns the preferred file extension (not including the ".") for files of this 086 * GeomReader's type. 087 * 088 * @return The preferred file extension for files of this readers type. 089 */ 090 @Override 091 public String getExtension() { 092 return EXTENSION; 093 } 094 095 /** 096 * Method that determines if this reader can read geometry from the specified input 097 * file. 098 * 099 * @param inputFile The input file containing the geometry to be read in. 100 * @return GeomReader.NO if the file format is not recognized by this reader. 101 * GeomReader.YES if the file format is definitely recognized by this reader. 102 * GeomReader.MAYBE if the file format might be readable by this reader, but 103 * that can't easily be determined without actually reading the file. 104 * @throws java.io.IOException If there is a problem reading from the specified 105 * file. 106 */ 107 @Override 108 public int canReadData(File inputFile) throws IOException { 109 110 int response = NO; 111 if (inputFile.isFile() && inputFile.exists()) { 112 String name = inputFile.getName(); 113 name = name.toLowerCase().trim(); 114 if (name.endsWith(".igs") || name.endsWith(".iges")) 115 response = YES; 116 } 117 118 return response; 119 } 120 121 /** 122 * Reads in an IGES geometry file from the specified input file and returns a 123 * {@link GeometryList} object that contains the geometry from the file. 124 * 125 * @param inputFile The input file containing the geometry to be read in. May not 126 * be null. 127 * @return A {@link GeometryList} object containing the geometry read in from the 128 * file. If the file has no readable geometry in it, then this list will have 129 * no elements in it (will have a size() of 0). 130 * @throws IOException If there is a problem reading the specified file. 131 */ 132 @Override 133 public GeometryList read(File inputFile) throws IOException { 134 requireNonNull(inputFile); 135 _warnings.clear(); 136 137 // Create an empty geometry list. 138 GeometryList output = GeomList.newInstance(); 139 140 // IGES files are required to be in ASCII with U.S. style number formatting. 141 // Get the default locale and save it. Then change the default locale to US. 142 Locale defLocale = Locale.getDefault(); 143 Locale.setDefault(Locale.US); 144 145 // Create a reader to access the IGES ASCII file. 146 try (RandomAccessFile in = new RandomAccessFile(inputFile, "r")) { 147 148 // Use the IGES library to do the actual reading of the file. 149 Part part = new Part(); 150 part.read(in); 151 152 // Store any error/warning messages. 153 _warnings.addAll(part.getErrors()); 154 155 // Get a list of all the entities read in from the IGES file. 156 List<Entity> entities = part.getEntities(); 157 158 // Copy the geometry from the IGES Part to the output list. 159 for (Entity entity : entities) { 160 if (entity instanceof GeomSSEntity) { 161 // We only care about entities that have GeomSS geometry in them. 162 GeomSSEntity geomEntity = (GeomSSEntity)entity; 163 164 // Only include entities that are not subsets of other entities (like lists). 165 if (!geomEntity.isUsedInList()) { 166 167 // Ignore blanked and subordinate entities. 168 //if (geomEntity.blankedStatus() < 1 && geomEntity.subordStatus() < 1) { 169 // Add the geometry to our output list. 170 GeomElement geom = geomEntity.getGeomElement(GTransform.IDENTITY); 171 if (geom != null) 172 output.add(geom); 173 else { 174 _warnings.add("GeomEntity has no GeomElement: " + geomEntity); 175 System.out.println(_warnings.get(_warnings.size()-1)); 176 } 177 178 /* 179 * } else { // Add a note that this was skipped to the 180 * warning list. StringBuffer msg = new StringBuffer(); 181 * msg.append(" "); 182 * msg.append(RESOURCES.getString("skippedWarning")); 183 * msg.append(" "); msg.append(geomEntity.getHeader()); 184 * msg.append(", blanked = "); 185 * msg.append(geomEntity.blankedStatus()); msg.append(", 186 * subordStatus = "); 187 * msg.append(geomEntity.subordStatus()); 188 * _warnings.add(msg.toString()); 189 } 190 */ 191 } 192 } 193 } 194 195 // If all we have is a GeomList, just output that. 196 if (output.size() == 1 && output.get(0) instanceof GeomList) 197 output = (GeomList)output.get(0); 198 199 // Store some of the IGES meta-data in the output list's user data. 200 String str = part.getStartSection().toString(); 201 if (!str.equals("")) 202 output.putUserData("IGESStartSection", str); 203 GlobalSection global = part.getGlobalSection(); 204 output.putUserData("IGESGrain", global.getGrainParameter()); 205 str = global.getProductName(); 206 if (!str.equals("")) { 207 output.putUserData("IGESProductName", str); 208 output.setName(str); 209 } 210 str = global.getFileName(); 211 if (!str.equals("")) 212 output.putUserData("IGESFileName", str); 213 str = global.getPreprocesorVersion(); 214 if (!str.equals("")) 215 output.putUserData("IGESPreprocesorVersion", str); 216 str = global.getDateTime(); 217 if (!str.equals("")) 218 output.putUserData("IGESDateTime", str); 219 str = global.getModDateTime(); 220 if (!str.equals("")) 221 output.putUserData("IGESModDateTime", str); 222 str = global.getAuthor(); 223 if (!str.equals("") && !str.equals("NULL")) 224 output.putUserData("IGESAuthor", str); 225 str = global.getOrganization(); 226 if (!str.equals("") && !str.equals("NULL")) 227 output.putUserData("IGESOrganization", str); 228 229 // Replace any generic lists with more specific ones if possible. 230 output = refineLists(output); 231 232 } finally { 233 // Restore the default locale. 234 Locale.setDefault(defLocale); 235 } 236 237 return output; 238 } 239 240 /** 241 * Recursively replace any generic lists with more specific ones if possible. 242 */ 243 private GeometryList refineLists(GeometryList list) { 244 245 // First look for any sub-lists. 246 int size = list.size(); 247 for (int i = 0; i < size; ++i) { 248 GeomElement element = (GeomElement)list.get(i); 249 if (element instanceof GeometryList) { 250 GeometryList geomList = (GeometryList)element; 251 GeometryList newList = refineLists(geomList); 252 if (newList != geomList) 253 list.set(i, newList); 254 } 255 } 256 257 // Is this a "PointString"? 258 boolean isType = true; 259 for (int i = 0; i < size; ++i) { 260 GeomElement element = (GeomElement)list.get(i); 261 if (!(element instanceof GeomPoint)) { 262 isType = false; 263 break; 264 } 265 } 266 if (isType) { 267 PointString newList = PointString.newInstance(list.getName()); 268 newList.putAllUserData(list.getAllUserData()); 269 newList.addAll(list); 270 return newList; 271 } 272 273 // Is this a "PointArray"? 274 isType = true; 275 for (int i = 0; i < size; ++i) { 276 GeomElement element = (GeomElement)list.get(i); 277 if (!(element instanceof PointString)) { 278 isType = false; 279 break; 280 } 281 } 282 if (isType) { 283 PointArray newList = PointArray.newInstance(list.getName()); 284 newList.putAllUserData(list.getAllUserData()); 285 newList.addAll(list); 286 return newList; 287 } 288 289 // Is this a "PointComponent"? 290 isType = true; 291 for (int i = 0; i < size; ++i) { 292 GeomElement element = (GeomElement)list.get(i); 293 if (!(element instanceof PointArray)) { 294 isType = false; 295 break; 296 } 297 } 298 if (isType) { 299 PointComponent newList = PointComponent.newInstance(list.getName()); 300 newList.putAllUserData(list.getAllUserData()); 301 newList.addAll(list); 302 return newList; 303 } 304 305 // Is this a "PointVehicle"? 306 isType = true; 307 for (int i = 0; i < size; ++i) { 308 GeomElement element = (GeomElement)list.get(i); 309 if (!(element instanceof PointComponent)) { 310 isType = false; 311 break; 312 } 313 } 314 if (isType) { 315 PointVehicle newList = PointVehicle.newInstance(list.getName()); 316 newList.putAllUserData(list.getAllUserData()); 317 newList.addAll(list); 318 return newList; 319 } 320 321 return list; 322 } 323 324 /** 325 * Returns <code>true</code>. This reader can write some entity types to an IGES file. 326 * 327 * @return true 328 */ 329 @Override 330 public boolean canWriteData() { 331 return true; 332 } 333 334 /** 335 * Writes out a geometry file for the geometry contained in the supplied 336 * {@link GeometryList} object. If the input geometry is not 3D, it will be forced to 337 * be 3D (by padding if there are too few or by truncating additional dimensions). 338 * 339 * @param outputFile The output File to which the geometry is to be written. May not 340 * be null. 341 * @param geometry The {@link GeometryList} object containing the geometry to be 342 * written out. May not be null. 343 * @throws IOException If there is a problem writing to the specified file. 344 */ 345 @Override 346 public void write(File outputFile, GeometryList geometry) throws IOException { 347 requireNonNull(outputFile); 348 _warnings.clear(); 349 if (!geometry.containsGeometry()) { 350 _warnings.add(RESOURCES.getString("noGeometryWarning")); 351 return; 352 } 353 354 // IGES files are required to be in ASCII with U.S. style number formatting. 355 // Get the default locale and save it. Then change the default locale to US. 356 Locale defLocale = Locale.getDefault(); 357 Locale.setDefault(Locale.US); 358 359 // Create a PrintWriter that writes to the specified ASCII file. 360 StackContext.enter(); 361 try (PrintWriter writer = new PrintWriter(outputFile, StandardCharsets.US_ASCII.name())) { 362 363 // Create an IGES Part to contain the exchange geometry. 364 Part part = new Part(); 365 GlobalSection global = part.getGlobalSection(); 366 367 // Set the units being used for this geometry. 368 Unit<Length> unit = geometry.getUnit(); 369 global.setUnit(unit); 370 371 // Look for IGES meta-data in the input list. 372 Object udata = geometry.getUserData("IGESStartSection"); 373 if (nonNull(udata)) 374 part.getStartSection().setStartSection((String)udata); 375 udata = geometry.getUserData("IGESGrain"); 376 if (nonNull(udata)) { 377 Parameter<Length> grain = (Parameter)udata; 378 global.setGrain(grain.getValue(unit)); 379 } 380 udata = geometry.getUserData("IGESProductName"); 381 if (nonNull(udata)) 382 global.setProductName((String)udata); 383 udata = geometry.getUserData("IGESModDateTime"); 384 if (nonNull(udata)) 385 global.setModDateTime((String)udata); 386 udata = geometry.getUserData("IGESAuthor"); 387 if (nonNull(udata)) 388 global.setAuthor((String)udata); 389 udata = geometry.getUserData("IGESOrganization"); 390 if (nonNull(udata)) 391 global.setOrganization((String)udata); 392 393 // Set the file name. 394 global.setFileName(outputFile.getName()); 395 396 // Recurse through list and create entities for as much of the input geometry as possible. 397 elementEntityMap = new FastMap(); 398 List<Entity> entities = part.getEntities(); 399 Parameter<Length> grain = global.getGrainParameter().times(100); 400 Parameter<Length> tol = Parameter.valueOf(0.001, SI.METER).to(unit); 401 if (grain.isGreaterThan(tol)) 402 tol = grain; 403 addGeomList(tol, part, 1, entities, geometry); 404 405 // Write out the exchange file. 406 part.write(writer); 407 408 // Store any error/warning messages. 409 _warnings.addAll(part.getErrors()); 410 411 elementEntityMap.clear(); 412 413 } finally { 414 StackContext.exit(); 415 416 // Restore the default locale. 417 Locale.setDefault(defLocale); 418 } 419 420 } 421 422 /** 423 * Recursively add a list of geometry objects to the Part's entity list. 424 * 425 * @param tol The tolerance to use when converting curves to NURBS. 426 * @param part The part that the entities are associated with. 427 * @param DEnum The line count from the start of the Directory Entry Section for 428 * the next entry (odd number). 429 * @param entityList The list of entities being aggregated. 430 * @param geometry The list of GeomElement objects to be added to the entity list. 431 * @return The next DEnum after adding this list of geometry elements. 432 */ 433 private int addGeomList(Parameter<Length> tol, Part part, int DEnum, List<Entity> entityList, GeometryList geometry) { 434 boolean elementAdded = false; // Prevent adding empty lists. 435 FastTable<Entity> childEntities = FastTable.newInstance(); 436 437 int size = geometry.size(); 438 for (int i = 0; i < size; ++i) { 439 GeomElement element = (GeomElement)geometry.get(i); 440 441 // First make sure this element has not already been added to the transfer. 442 Entity e = elementEntityMap.get(element); 443 if (nonNull(e)) { 444 // Element is already a part of this transfer, but make a part of this list. 445 elementAdded = true; 446 childEntities.add(e); 447 continue; 448 } 449 450 // Deal with curves that are subranged onto a surface as a special case. 451 if (element instanceof SubrangeCurve) { 452 SubrangeCurve subCrv = (SubrangeCurve)element; 453 int numEntities = childEntities.size(); 454 if (subCrv.getChild() instanceof Surface) { 455 DEnum = handleCurveOnSurface(subCrv, DEnum, part, entityList, tol, childEntities); 456 } 457 if (numEntities != childEntities.size()) 458 elementAdded = true; 459 else 460 _warnings.add(MessageFormat.format(RESOURCES.getString("igesSkipUnsupported"), 461 element.getClass().getName(), element.getID())); 462 continue; 463 } 464 465 // Deal with a subrange surface as a special case. 466 if (element instanceof SubrangeSurface) { 467 SubrangeSurface subSrf = (SubrangeSurface)element; 468 int numEntities = childEntities.size(); 469 DEnum = handleSubrangeSurface(subSrf, DEnum, part, entityList, tol, childEntities); 470 if (numEntities != childEntities.size()) 471 elementAdded = true; 472 else 473 _warnings.add(MessageFormat.format(RESOURCES.getString("igesSkipUnsupported"), 474 element.getClass().getName(), element.getID())); 475 continue; 476 } 477 478 // Try to create an Entity for this element. 479 e = EntityFactory.create(part, DEnum, element); 480 if (nonNull(e)) { 481 entityList.add(e); 482 childEntities.add(e); 483 elementEntityMap.put(element, e); 484 elementAdded = true; 485 DEnum += 2; // Each Directory Entry takes 2 lines. 486 487 } else if (element instanceof GeometryList) { 488 // It's a list, so recurse down into it. 489 int oldDEnum = DEnum; 490 DEnum = addGeomList(tol, part, DEnum, entityList, (GeometryList)element); 491 if (oldDEnum != DEnum) { 492 elementAdded = true; 493 childEntities.add(entityList.get(entityList.size() - 1)); 494 } 495 496 } else 497 _warnings.add(MessageFormat.format(RESOURCES.getString("igesSkipUnsupported"), 498 element.getClass().getName(), element.getID())); 499 500 } // Next i 501 502 // Create an entity for the overall list. 503 if (elementAdded) { 504 Entity e = EntityFactory.createList(part, DEnum, childEntities, geometry.getName()); 505 if (nonNull(e)) { 506 entityList.add(e); 507 DEnum += 2; // Each Directory Entry takes 2 lines. 508 } 509 } 510 511 FastTable.recycle(childEntities); 512 513 return DEnum; 514 } 515 516 /** 517 * Handles the special case of a subrange curve on a surface. 518 * 519 * @param subCrv The subrange curve on a surface to be transferred. 520 * @param DEnum The current DE pointer value. 521 * @param part The part this curve is associated with. 522 * @param entityList The list of all the entities being transferred. 523 * @param tol The tolerance to use when converting curves to NURBS. 524 * @param childEntities The entities that are a part of the current geometry list 525 * being transferred. 526 * @return The DEnum incremented to account for the new entities added to the transfer 527 * by this method. 528 */ 529 private int handleCurveOnSurface(SubrangeCurve subCrv, int DEnum, Part part, List<Entity> entityList, Parameter<Length> tol, FastTable<Entity> childEntities) { 530 531 // Try to create an Entity for the surface that the curve is on. 532 Surface Ssrf = (Surface)subCrv.getChild(); 533 534 // First see if the Ssrf has been added to the transfer already. 535 Entity Se = elementEntityMap.get(Ssrf); 536 if (isNull(Se)) { 537 // Entity has not already been stored, so create a new one. 538 Se = EntityFactory.create(part, DEnum, Ssrf); 539 if (nonNull(Se)) { 540 entityList.add(Se); 541 DEnum += 2; 542 } 543 } 544 if (isNull(Se)) { 545 _warnings.add(MessageFormat.format(RESOURCES.getString("igesSkipUnsupported"), 546 Ssrf.getClass().getName(), Ssrf.getID())); 547 return DEnum; // Failed to create the transfer. 548 } 549 int Sptr = Se.getDENum(); 550 551 // Store a mapping of the Ssrf surface to the Se entity in case it is used again. 552 elementEntityMap.put(Ssrf, Se); 553 554 // Now add the (u,v) parametric curve. 555 NurbsCurve Bcrv = subCrv.getParPosition().toNurbs(tol); 556 // Must change to transfer units or scaling will be incorrect. 557 Bcrv = changeCurveUnits(Bcrv, part.getGlobalSection().getUnit()); 558 int Bptr = DEnum; 559 Entity Be = EntityFactory.create(part, Bptr, Bcrv); 560 if (isNull(Be)) { 561 _warnings.add(MessageFormat.format(RESOURCES.getString("igesSkipUnsupported"), 562 Bcrv.getClass().getName(), Bcrv.getID())); 563 return DEnum; // Failed to create transfer. 564 } 565 entityList.add(Be); 566 elementEntityMap.put(Bcrv, Be); 567 DEnum += 2; 568 569 // Now add the real-space curve. 570 Curve Ccrv = subCrv.toNurbs(tol); // Convert to NURBS. 571 int Cptr = DEnum; 572 Entity Ce = EntityFactory.create(part, Cptr, Ccrv); 573 if (nonNull(Ce)) { 574 entityList.add(Ce); 575 DEnum += 2; 576 577 // Finally, add the curve on surface entity. 578 Entity crvOnSrfe = new Entity142_CurveOnSurface(part, DEnum, subCrv.getName(), Sptr, Bptr, Cptr); 579 entityList.add(crvOnSrfe); 580 DEnum += 2; 581 if (nonNull(childEntities)) 582 childEntities.add(crvOnSrfe); 583 elementEntityMap.put(subCrv, crvOnSrfe); 584 585 } else 586 _warnings.add(MessageFormat.format(RESOURCES.getString("igesSkipUnsupported"), 587 Ccrv.getClass().getName(), Ccrv.getID())); 588 589 return DEnum; 590 } 591 592 /** 593 * Handles the special case of a subrange or trimmed surface. 594 * 595 * @param subSrf The subrange surface being transferred. 596 * @param DEnum The current DE pointer value. 597 * @param part The part this curve is associated with. 598 * @param entityList The list of all the entities being transferred. 599 * @param tol The tolerance to use when converting curves to NURBS. 600 * @param childEntities The entities that are a part of the current geometry list 601 * being transferred. 602 * @return The DEnum incremented to account for the new entities added to the transfer 603 * by this method. 604 */ 605 private int handleSubrangeSurface(SubrangeSurface subSrf, int DEnum, Part part, List<Entity> entityList, Parameter<Length> tol, FastTable<Entity> childEntities) { 606 // Get the surface being trimmed. 607 Surface Ssrf = (Surface)subSrf.getChild(); 608 609 // First see if the Ssrf has been added to the transfer already. 610 Entity Se = elementEntityMap.get(Ssrf); 611 if (isNull(Se)) { 612 // Entity has not already been stored, so create a new one. 613 Se = EntityFactory.create(part, DEnum, Ssrf); 614 if (nonNull(Se)) { 615 entityList.add(Se); 616 DEnum += 2; 617 } 618 } 619 if (isNull(Se)) { 620 _warnings.add(MessageFormat.format(RESOURCES.getString("igesSkipUnsupported"), 621 Ssrf.getClass().getName(), Ssrf.getID())); 622 return DEnum; // Failed to create the transfer. 623 } 624 int Sptr = Se.getDENum(); 625 626 // Get the parametric position surface (assumed to be a TFI surface -- what if it isn't?). 627 Surface parSrf = subSrf.getParPosition(); 628 629 // Get the 4 boundary parametric space curves oriented in a counter-clockwise direction. 630 NurbsCurve[] parBoundaryCrvs = new NurbsCurve[4]; 631 parBoundaryCrvs[0] = parSrf.getS0Curve().toNurbs(tol); 632 parBoundaryCrvs[1] = parSrf.getT1Curve().toNurbs(tol); 633 parBoundaryCrvs[2] = parSrf.getS1Curve().reverse().toNurbs(tol); 634 parBoundaryCrvs[3] = parSrf.getT0Curve().reverse().toNurbs(tol); 635 636 // Add each of the parametric boundary curves to the transfer. 637 Unit<Length> unit = part.getGlobalSection().getUnit(); 638 FastTable<Integer> segDEPtrs = FastTable.newInstance(); 639 for (int i = 0; i < 4; ++i) { 640 NurbsCurve crvi = parBoundaryCrvs[i]; 641 642 // Must change to transfer units or scaling will be incorrect. 643 crvi = changeCurveUnits(crvi, unit); 644 645 Entity segE = EntityFactory.create(part, DEnum, crvi); 646 if (isNull(segE)) { 647 _warnings.add(MessageFormat.format(RESOURCES.getString("igesSkipUnsupported"), 648 crvi.getClass().getName(), crvi.getID())); 649 return DEnum; // Failed to create transfer. 650 } 651 entityList.add(segE); 652 segDEPtrs.add(DEnum); 653 DEnum += 2; 654 } 655 656 // Add a composite curve made up of the parametric segments to the transfer. 657 Entity Be = new Entity102_CompositeCurve(part, DEnum, null, segDEPtrs); 658 entityList.add(Be); 659 int Bptr = DEnum; 660 DEnum += 2; 661 FastTable.recycle(segDEPtrs); 662 663 // Create a real-space composite boundary curve to adhear to the contract for Entity 142. 664 NurbsCurve[] boundaryCrvs = new NurbsCurve[4]; 665 boundaryCrvs[0] = subSrf.getS0Curve().toNurbs(tol); 666 boundaryCrvs[1] = subSrf.getT1Curve().toNurbs(tol); 667 boundaryCrvs[2] = subSrf.getS1Curve().reverse().toNurbs(tol); 668 boundaryCrvs[3] = subSrf.getT0Curve().reverse().toNurbs(tol); 669 NurbsCurve Ccrv = CurveUtils.connectCurves(boundaryCrvs); 670 671 // Add the composite boundary curve to the transfer. 672 Entity Ce = EntityFactory.create(part, DEnum, Ccrv); 673 if (isNull(Ce)) { 674 _warnings.add(MessageFormat.format(RESOURCES.getString("igesSkipUnsupported"), 675 Ccrv.getClass().getName(), Ccrv.getID())); 676 return DEnum; // Failed to create transfer. 677 } 678 entityList.add(Ce); 679 int Cptr = DEnum; 680 DEnum += 2; 681 682 // Add a curve on surface entity to the transfer using the composite curve. 683 Entity Oe = new Entity142_CurveOnSurface(part, DEnum, null, Sptr, Bptr, Cptr); 684 entityList.add(Oe); 685 int PTO = DEnum; 686 DEnum += 2; 687 688 // Finally, add the trimmed surface to the transfer. 689 Entity trimSrfe = new Entity144_TrimmedSurface(part, DEnum, subSrf, Sptr, PTO); 690 entityList.add(trimSrfe); 691 DEnum += 2; 692 if (nonNull(childEntities)) 693 childEntities.add(trimSrfe); 694 elementEntityMap.put(subSrf, trimSrfe); 695 696 return DEnum; 697 } 698 699 /** 700 * Return a new curve with the same numerical values as the 1st curve, but with the 701 * units changed to those specified. 702 * 703 * @param crv The curve to have the units changed. 704 * @param unit The new unit for the output curve. 705 * @return A curve with the same numerical values as the "crv", but with the units 706 * changed to "unit". 707 */ 708 private static NurbsCurve changeCurveUnits(NurbsCurve crv, Unit<Length> unit) { 709 StackContext.enter(); 710 try { 711 712 List<ControlPoint> oldCPList = crv.getControlPoints(); 713 FastTable<ControlPoint> newCPList = FastTable.newInstance(); 714 for (ControlPoint cp : oldCPList) { 715 Point p = cp.getPoint(); 716 double w = cp.getWeight(); 717 Point pnew = Point.valueOf(p.getValue(0), p.getValue(1), 0, unit); 718 newCPList.add(ControlPoint.valueOf(pnew, w)); 719 } 720 crv = BasicNurbsCurve.newInstance(newCPList, crv.getKnotVector()); 721 return StackContext.outerCopy((BasicNurbsCurve)crv); 722 723 } finally { 724 StackContext.exit(); 725 } 726 } 727 728 /** 729 * This method always returns <code>true</code> as IGES files do encode the units that 730 * are being used though the list of available units is limited. 731 * 732 * @return this implementation always returns true 733 * @see #setFileUnits(javax.measure.unit.Unit) 734 */ 735 @Override 736 public boolean isUnitAware() { 737 return true; 738 } 739}