View Javadoc

    1   /*
    2    * Licensed to the Apache Software Foundation (ASF) under one or more
    3    * contributor license agreements.  See the NOTICE file distributed with
    4    * this work for additional information regarding copyright ownership.
    5    * The ASF licenses this file to You under the Apache License, Version 2.0
    6    * (the "License"); you may not use this file except in compliance with
    7    * the License.  You may obtain a copy of the License at
    8    *
    9    *      http://www.apache.org/licenses/LICENSE-2.0
    10   *
    11   * Unless required by applicable law or agreed to in writing, software
    12   * distributed under the License is distributed on an "AS IS" BASIS,
    13   * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
    14   * See the License for the specific language governing permissions and
    15   * limitations under the License.
    16   */
    17  package org.apache.commons.geometry.io.euclidean.threed;
    18
    19  import java.net.URL;
    20  import java.nio.file.Path;
    21  import java.util.Collection;
    22  import java.util.stream.Stream;
    23
    24  import org.apache.commons.geometry.euclidean.threed.BoundarySource3D;
    25  import org.apache.commons.geometry.euclidean.threed.PlaneConvexSubset;
    26  import org.apache.commons.geometry.euclidean.threed.Triangle3D;
    27  import org.apache.commons.geometry.euclidean.threed.mesh.TriangleMesh;
    28  import org.apache.commons.geometry.io.core.GeometryFormat;
    29  import org.apache.commons.geometry.io.core.input.FileGeometryInput;
    30  import org.apache.commons.geometry.io.core.input.GeometryInput;
    31  import org.apache.commons.geometry.io.core.input.UrlGeometryInput;
    32  import org.apache.commons.geometry.io.core.output.FileGeometryOutput;
    33  import org.apache.commons.geometry.io.core.output.GeometryOutput;
    34  import org.apache.commons.numbers.core.Precision;
    35
    36  /** Utility class providing convenient access to 3D IO functionality. The static read and write methods here
    37   * delegate to a default {@link #getDefaultManager() BoundaryIOManager3D} instance. The default
    38   * configuration should be sufficient for most purposes. If customization is required, consider directly
    39   * creating and configuring and a {@link BoundaryIOManager3D} instance.
    40   *
    41   * <p><strong>Examples</strong></p>
    42   * <p>The example below reads an OBJ file as a stream of triangles, transforms each triangle, and writes the
    43   * result as a CSV file. The data formats are inferred from the input and output file extensions.</p>
    44   * <pre>
    45   * GeometryInput input = new FileGeometryInput(Paths.get("orig.obj"));
    46   * GeometryOutput scaledOutput = new FileGeometryOutput(Paths.get("scaled.csv"));
    47   * AffineTransformMatrix3D transform = AffineTransformMatrix3D.createScale(2);
    48   *
    49   * // Use the input triangle stream in a try-with-resources statement to ensure
    50   * // all resources are properly released.
    51   * try (Stream&lt;Triangle3D&gt; stream = IO3D.triangles(input, null, precision)) {
    52   *      IO3D.write(stream.map(t -&gt; t.transform(transform)), scaledOutput, null);
    53   * }
    54   * </pre>
    55   * @see BoundaryIOManager3D
    56   */
    57  public final class IO3D {
    58
    59      /** Utility class; no instantiation. */
    60      private IO3D() {}
    61
    62      /** Get a {@link FacetDefinitionReader} for reading facet information from the given file path.
    63       * The data format is determined by the file extension of the argument.
    64       * @param path path to obtain a reader for
    65       * @return facet definition reader
    66       * @throws IllegalArgumentException if no handler has been registered with the
    67       *      {@link #getDefaultManager() default manager} for the input format
    68       * @throws IllegalStateException if a data format error occurs
    69       * @throws java.io.UncheckedIOException if an I/O error occurs
    70       * @see BoundaryIOManager3D#facetDefinitionReader(GeometryInput, GeometryFormat)
    71       */
    72      public static FacetDefinitionReader facetDefinitionReader(final Path path) {
    73          return facetDefinitionReader(new FileGeometryInput(path), null);
    74      }
    75
    76      /** Get a {@link FacetDefinitionReader} for reading facet information from the given URL.
    77       * The data format is determined by the file extension of the argument.
    78       * @param url URL to read from
    79       * @return facet definition reader
    80       * @throws IllegalArgumentException if no handler has been registered with the
    81       *      {@link #getDefaultManager() default manager} for the input format
    82       * @throws IllegalStateException if a data format error occurs
    83       * @throws java.io.UncheckedIOException if an I/O error occurs
    84       * @see BoundaryIOManager3D#facetDefinitionReader(GeometryInput, GeometryFormat)
    85       */
    86      public static FacetDefinitionReader facetDefinitionReader(final URL url) {
    87          return facetDefinitionReader(new UrlGeometryInput(url), null);
    88      }
    89
    90      /** Get a {@link FacetDefinitionReader} for reading facet information from the given input.
    91       * @param in input to read from
    92       * @param fmt format of the input; if null, the format is determined implicitly from the
    93       *      file extension of the input {@link GeometryInput#getFileName() file name}
    94       * @return facet definition reader
    95       * @throws IllegalArgumentException if no handler has been registered with the
    96       *      {@link #getDefaultManager() default manager} for the input format
    97       * @throws IllegalStateException if a data format error occurs
    98       * @throws java.io.UncheckedIOException if an I/O error occurs
    99       * @see BoundaryIOManager3D#facetDefinitionReader(GeometryInput, GeometryFormat)
    100      */
    101     public static FacetDefinitionReader facetDefinitionReader(final GeometryInput in, final GeometryFormat fmt) {
    102         return getDefaultManager().facetDefinitionReader(in, fmt);
    103     }
    104
    105     /** Return a {@link Stream} providing access to all facets from the given file path. The data format
    106      * is determined by the file extension of the argument.
    107      *
    108      * <p>The underlying input stream is closed when the returned stream is closed. Callers should
    109      * therefore use the returned stream in a try-with-resources statement to ensure that all
    110      * resources are properly released. Ex:
    111      * </p>
    112      * <pre>
    113      *  try (Stream&lt;FacetDefinition&gt; stream = IO3D.facets(path)) {
    114      *      // access stream content
    115      *  }
    116      * </pre>
    117      * <p>The following exceptions may be thrown during stream iteration:
    118      *  <ul>
    119      *      <li>{@link IllegalStateException} if a data format error occurs</li>
    120      *      <li>{@link java.io.UncheckedIOException UncheckedIOException} if an I/O error occurs</li>
    121      *  </ul>
    122      * @param path file path to read from
    123      * @return stream providing access to the facets in the specified file
    124      * @throws IllegalArgumentException if no handler has been registered with the
    125      *      {@link #getDefaultManager() default manager} for the input format
    126      * @throws IllegalStateException if a data format error occurs during stream creation
    127      * @throws java.io.UncheckedIOException if an I/O error occurs during stream creation
    128      * @see BoundaryIOManager3D#facets(GeometryInput, GeometryFormat)
    129      */
    130     public static Stream<FacetDefinition> facets(final Path path) {
    131         return facets(new FileGeometryInput(path), null);
    132     }
    133
    134     /** Return a {@link Stream} providing access to all facets from the given URL. he data format
    135      * is determined by the file extension of the argument.
    136      *
    137      * <p>The underlying input stream is closed when the returned stream is closed. Callers should
    138      * therefore use the returned stream in a try-with-resources statement to ensure that all
    139      * resources are properly released. Ex:
    140      * </p>
    141      * <pre>
    142      *  try (Stream&lt;FacetDefinition&gt; stream = IO3D.facets(url)) {
    143      *      // access stream content
    144      *  }
    145      * </pre>
    146      * <p>The following exceptions may be thrown during stream iteration:
    147      *  <ul>
    148      *      <li>{@link IllegalStateException} if a data format error occurs</li>
    149      *      <li>{@link java.io.UncheckedIOException UncheckedIOException} if an I/O error occurs</li>
    150      *  </ul>
    151      * @param url URL to read from
    152      * @return stream providing access to the facets from the specified URL
    153      * @throws IllegalArgumentException if no handler has been registered with the
    154      *      {@link #getDefaultManager() default manager} for the input format
    155      * @throws IllegalStateException if a data format error occurs during stream creation
    156      * @throws java.io.UncheckedIOException if an I/O error occurs during stream creation
    157      * @see BoundaryIOManager3D#facets(GeometryInput, GeometryFormat)
    158      */
    159     public static Stream<FacetDefinition> facets(final URL url) {
    160         return facets(new UrlGeometryInput(url), null);
    161     }
    162
    163     /** Return a {@link Stream} providing access to all facets from the given input. The underlying input
    164      * stream is closed when the returned stream is closed. Callers should therefore use the returned stream
    165      * in a try-with-resources statement to ensure that all resources are properly released.
    166      * <pre>
    167      *  try (Stream&lt;FacetDefinition&gt; stream = IO3D.facets(in, fmt)) {
    168      *      // access stream content
    169      *  }
    170      * </pre>
    171      * <p>The following exceptions may be thrown during stream iteration:
    172      *  <ul>
    173      *      <li>{@link IllegalStateException} if a data format error occurs</li>
    174      *      <li>{@link java.io.UncheckedIOException UncheckedIOException} if an I/O error occurs</li>
    175      *  </ul>
    176      * @param in input to read from
    177      * @param fmt format of the input; if null, the format is determined implicitly from the
    178      *      file extension of the input {@link GeometryInput#getFileName() file name}
    179      * @return stream providing access to the facets in the input
    180      * @throws IllegalArgumentException if no read handler has been registered with the
    181      *      {@link #getDefaultManager() default manager} for the input format
    182      * @throws IllegalStateException if a data format error occurs during stream creation
    183      * @throws java.io.UncheckedIOException if an I/O error occurs during stream creation
    184      * @see BoundaryIOManager3D#facets(GeometryInput, GeometryFormat)
    185      */
    186     public static Stream<FacetDefinition> facets(final GeometryInput in, final GeometryFormat fmt) {
    187         return getDefaultManager().facets(in, fmt);
    188     }
    189
    190     /** Return a {@link Stream} providing access to all boundaries from the given file path. The
    191      * data format is determined by the file extension of the argument.
    192      *
    193      * <p>The underlying input stream is closed when the returned stream is closed. Callers should
    194      * therefore use the returned stream in a try-with-resources statement to ensure that all
    195      * resources are properly released. Ex:
    196      * </p>
    197      * <pre>
    198      *  try (Stream&lt;PlaneConvexSubset&gt; stream = IO3D.boundaries(path, precision)) {
    199      *      // access stream content
    200      *  }
    201      * </pre>
    202      * <p>The following exceptions may be thrown during stream iteration:
    203      *  <ul>
    204      *      <li>{@link IllegalArgumentException} if mathematically invalid data is encountered</li>
    205      *      <li>{@link IllegalStateException} if a data format error occurs</li>
    206      *      <li>{@link java.io.UncheckedIOException UncheckedIOException} if an I/O error occurs</li>
    207      *  </ul>
    208      * @param path file path to read from
    209      * @param precision precision context used for floating point comparisons
    210      * @return stream providing access to the boundaries in the specified file
    211      * @throws IllegalArgumentException if no read handler has been registered with the
    212      *      {@link #getDefaultManager() default manager} for the input format
    213      * @throws IllegalStateException if a data format error occurs during stream creation
    214      * @throws java.io.UncheckedIOException if an I/O error occurs during stream creation
    215      * @see BoundaryIOManager3D#boundaries(GeometryInput, GeometryFormat, Precision.DoubleEquivalence)
    216      */
    217     public static Stream<PlaneConvexSubset> boundaries(final Path path, final Precision.DoubleEquivalence precision) {
    218         return boundaries(new FileGeometryInput(path), null, precision);
    219     }
    220
    221     /** Return a {@link Stream} providing access to all boundaries from the given URL. The data
    222      * format is determined by the file extension of the argument.
    223      *
    224      * <p>The underlying input stream is closed when the returned stream is closed. Callers should
    225      * therefore use the returned stream in a try-with-resources statement to ensure that all
    226      * resources are properly released. Ex:
    227      * </p>
    228      * <pre>
    229      *  try (Stream&lt;PlaneConvexSubset&gt; stream = IO3D.boundaries(url, precision)) {
    230      *      // access stream content
    231      *  }
    232      * </pre>
    233      * <p>The following exceptions may be thrown during stream iteration:
    234      *  <ul>
    235      *      <li>{@link IllegalArgumentException} if mathematically invalid data is encountered</li>
    236      *      <li>{@link IllegalStateException} if a data format error occurs</li>
    237      *      <li>{@link java.io.UncheckedIOException UncheckedIOException} if an I/O error occurs</li>
    238      *  </ul>
    239      * @param url URL to read from
    240      * @param precision precision context used for floating point comparisons
    241      * @return stream providing access to the boundaries in the specified URL
    242      * @throws IllegalArgumentException if no read handler has been registered with the
    243      *      {@link #getDefaultManager() default manager} for the input format
    244      * @throws IllegalStateException if a data format error occurs during stream creation
    245      * @throws java.io.UncheckedIOException if an I/O error occurs during stream creation
    246      * @see BoundaryIOManager3D#boundaries(GeometryInput, GeometryFormat, Precision.DoubleEquivalence)
    247      */
    248     public static Stream<PlaneConvexSubset> boundaries(final URL url, final Precision.DoubleEquivalence precision) {
    249         return boundaries(new UrlGeometryInput(url), null, precision);
    250     }
    251
    252     /** Return a {@link Stream} providing access to all boundaries from the given input. The underlying input
    253      * stream is closed when the returned stream is closed. Callers should therefore use the returned stream
    254      * in a try-with-resources statement to ensure that all resources are properly released. Ex:
    255      * <pre>
    256      *  try (Stream&lt;H&gt; stream = IO3D.boundaries(in, fmt, precision)) {
    257      *      // access stream content
    258      *  }
    259      *  </pre>
    260      * <p>The following exceptions may be thrown during stream iteration:
    261      *  <ul>
    262      *      <li>{@link IllegalArgumentException} if mathematically invalid data is encountered</li>
    263      *      <li>{@link IllegalStateException} if a data format error occurs</li>
    264      *      <li>{@link java.io.UncheckedIOException UncheckedIOException} if an I/O error occurs</li>
    265      *  </ul>
    266      * @param in input to read boundaries from
    267      * @param fmt format of the input; if null, the format is determined implicitly from the
    268      *      file extension of the input {@link GeometryInput#getFileName() file name}
    269      * @param precision precision context used for floating point comparisons
    270      * @return stream providing access to the boundaries in the input
    271      * @throws IllegalArgumentException if no read handler is registered with the
    272      *      {@link #getDefaultManager() default manager} for the input format
    273      * @throws IllegalStateException if a data format error occurs during stream creation
    274      * @throws java.io.UncheckedIOException if an I/O error occurs during stream creation
    275      * @see BoundaryIOManager3D#boundaries(GeometryInput, GeometryFormat, Precision.DoubleEquivalence)
    276      */
    277     public static Stream<PlaneConvexSubset> boundaries(final GeometryInput in, final GeometryFormat fmt,
    278             final Precision.DoubleEquivalence precision) {
    279         return getDefaultManager().boundaries(in, fmt, precision);
    280     }
    281
    282     /** Return a {@link Stream} providing access to all triangles from the given file path. The data
    283      * format is determined by the file extension of the argument.
    284      *
    285      * <p>The underlying input stream is closed when the returned stream is closed. Callers should
    286      * therefore use the returned stream in a try-with-resources statement to ensure that all
    287      * resources are properly released. Ex:
    288      * </p>
    289      * <pre>
    290      *  try (Stream&lt;Triangle3D&gt; stream = IO3D.triangles(path, precision)) {
    291      *      // access stream content
    292      *  }
    293      * </pre>
    294      * <p>The following exceptions may be thrown during stream iteration:
    295      *  <ul>
    296      *      <li>{@link IllegalArgumentException} if mathematically invalid data is encountered</li>
    297      *      <li>{@link IllegalStateException} if a data format error occurs</li>
    298      *      <li>{@link java.io.UncheckedIOException UncheckedIOException} if an I/O error occurs</li>
    299      *  </ul>
    300      * @param path file path to read from
    301      * @param precision precision context used for floating point comparisons
    302      * @return stream providing access to the triangles in the specified file
    303      * @throws IllegalArgumentException if no read handler is registered with the
    304      *      {@link #getDefaultManager() default manager} for the input format
    305      * @throws IllegalStateException if a data format error occurs during stream creation
    306      * @throws java.io.UncheckedIOException if an I/O error occurs during stream creation
    307      * @see BoundaryIOManager3D#triangles(GeometryInput, GeometryFormat, Precision.DoubleEquivalence)
    308      */
    309     public static Stream<Triangle3D> triangles(final Path path, final Precision.DoubleEquivalence precision) {
    310         return triangles(new FileGeometryInput(path), null, precision);
    311     }
    312
    313     /** Return a {@link Stream} providing access to all triangles from the given URL. The data format
    314      * is determined by the file extension of the argument.
    315      *
    316      * <p>The underlying input stream is closed when the returned stream is closed. Callers should
    317      * therefore use the returned stream in a try-with-resources statement to ensure that all
    318      * resources are properly released. Ex:
    319      * </p>
    320      * <pre>
    321      *  try (Stream&lt;Triangle3D&gt; stream = IO3D.triangles(url, precision)) {
    322      *      // access stream content
    323      *  }
    324      * </pre>
    325      * <p>The following exceptions may be thrown during stream iteration:
    326      *  <ul>
    327      *      <li>{@link IllegalArgumentException} if mathematically invalid data is encountered</li>
    328      *      <li>{@link IllegalStateException} if a data format error occurs</li>
    329      *      <li>{@link java.io.UncheckedIOException UncheckedIOException} if an I/O error occurs</li>
    330      *  </ul>
    331      * @param url URL to read from
    332      * @param precision precision context used for floating point comparisons
    333      * @return stream providing access to the triangles from the specified URL
    334      * @throws IllegalArgumentException if no read handler is registered with the
    335      *      {@link #getDefaultManager() default manager} for the input format
    336      * @throws IllegalStateException if a data format error occurs during stream creation
    337      * @throws java.io.UncheckedIOException if an I/O error occurs during stream creation
    338      * @see BoundaryIOManager3D#triangles(GeometryInput, GeometryFormat, Precision.DoubleEquivalence)
    339      */
    340     public static Stream<Triangle3D> triangles(final URL url, final Precision.DoubleEquivalence precision) {
    341         return triangles(new UrlGeometryInput(url), null, precision);
    342     }
    343
    344     /** Return a {@link Stream} providing access to all triangles from the given input. The underlying input
    345      * stream is closed when the returned stream is closed. Callers should therefore use the returned stream
    346      * in a try-with-resources statement to ensure that all resources are properly released.
    347      * <pre>
    348      *  try (Stream&lt;Triangle3D&gt; stream = IO3D.triangles(in, fmt, precision)) {
    349      *      // access stream content
    350      *  }
    351      * </pre>
    352      * <p>The following exceptions may be thrown during stream iteration:
    353      *  <ul>
    354      *      <li>{@link IllegalArgumentException} if mathematically invalid data is encountered</li>
    355      *      <li>{@link IllegalStateException} if a data format error occurs</li>
    356      *      <li>{@link java.io.UncheckedIOException UncheckedIOException} if an I/O error occurs</li>
    357      *  </ul>
    358      * @param in input to read from
    359      * @param fmt format of the input; if null, the format is determined implicitly from the
    360      *      file extension of the input {@link GeometryInput#getFileName() file name}
    361      * @param precision precision context used for floating point comparisons
    362      * @return stream providing access to the triangles in the input
    363      * @throws IllegalArgumentException if no read handler is registered with the
    364      *      {@link #getDefaultManager() default manager} for the input format
    365      * @throws IllegalStateException if a data format error occurs during stream creation
    366      * @throws java.io.UncheckedIOException if an I/O error occurs during stream creation
    367      * @see BoundaryIOManager3D#triangles(GeometryInput, GeometryFormat, Precision.DoubleEquivalence)
    368      */
    369     public static Stream<Triangle3D> triangles(final GeometryInput in, final GeometryFormat fmt,
    370             final Precision.DoubleEquivalence precision) {
    371         return getDefaultManager().triangles(in, fmt, precision);
    372     }
    373
    374     /** Return a {@link BoundarySource3D} containing all boundaries from the file at the
    375      * given path. The data format is determined from the file extension. A runtime exception may be
    376      * thrown if mathematically invalid boundaries are encountered.
    377      * @param path file path to read from
    378      * @param precision precision context used for floating point comparisons
    379      * @return object containing all boundaries from the file at the given path
    380      * @throws IllegalArgumentException if mathematically invalid data is encountered or no read handler
    381      *      is registered with the {@link #getDefaultManager() default manager} for the input format
    382      * @throws IllegalStateException if a data format error occurs
    383      * @throws java.io.UncheckedIOException if an I/O error occurs
    384      * @see BoundaryIOManager3D#read(GeometryInput, GeometryFormat, Precision.DoubleEquivalence)
    385      */
    386     public static BoundarySource3D read(final Path path, final Precision.DoubleEquivalence precision) {
    387         return read(new FileGeometryInput(path), null, precision);
    388     }
    389
    390     /** Return a {@link BoundarySource3D} containing all boundaries from the given URL. The data
    391      * format is determined from the file extension of the URL path. A runtime exception may be
    392      * thrown if mathematically invalid boundaries are encountered.
    393      * @param url URL to read from
    394      * @param precision precision context used for floating point comparisons
    395      * @return object containing all boundaries from the given URL
    396      * @throws IllegalArgumentException if mathematically invalid data is encountered or no read handler
    397      *      is registered with the {@link #getDefaultManager() default manager} for the input format
    398      * @throws IllegalStateException if a data format error occurs
    399      * @throws java.io.UncheckedIOException if an I/O error occurs
    400      * @see BoundaryIOManager3D#read(GeometryInput, GeometryFormat, Precision.DoubleEquivalence)
    401      */
    402     public static BoundarySource3D read(final URL url, final Precision.DoubleEquivalence precision) {
    403         return read(new UrlGeometryInput(url), null, precision);
    404     }
    405
    406     /** Return a {@link BoundarySource3D} containing all boundaries from the given input. A runtime
    407      * exception may be thrown if mathematically invalid boundaries are encountered.
    408      * @param in input to read boundaries from
    409      * @param fmt format of the input; if null, the format is determined implicitly from the
    410      *      file extension of the input {@link GeometryInput#getFileName() file name}
    411      * @param precision precision context used for floating point comparisons
    412      * @return object containing all boundaries from the input
    413      * @throws IllegalArgumentException if mathematically invalid data is encountered or no read handler
    414      *      is registered with the {@link #getDefaultManager() default manager} for the input format
    415      * @throws IllegalStateException if a data format error occurs
    416      * @throws java.io.UncheckedIOException if an I/O error occurs
    417      * @see BoundaryIOManager3D#read(GeometryInput, GeometryFormat, Precision.DoubleEquivalence)
    418      */
    419     public static BoundarySource3D read(final GeometryInput in, final GeometryFormat fmt,
    420             final Precision.DoubleEquivalence precision) {
    421         return getDefaultManager().read(in, fmt, precision);
    422     }
    423
    424     /** Return a {@link TriangleMesh} containing all triangles from the given file path. The data
    425      * format is determined from the file extension of the path. A runtime exception may be
    426      * thrown if mathematically invalid boundaries are encountered.
    427      * @param path file path to read from
    428      * @param precision precision context used for floating point comparisons
    429      * @return mesh containing all triangles from the given file path
    430      * @throws IllegalArgumentException if mathematically invalid data is encountered or no read handler
    431      *      is registered with the {@link #getDefaultManager() default manager} for the input format
    432      * @throws IllegalStateException if a data format error occurs
    433      * @throws java.io.UncheckedIOException if an I/O error occurs
    434      * @see BoundaryIOManager3D#readTriangleMesh(GeometryInput, GeometryFormat, Precision.DoubleEquivalence)
    435      */
    436     public static TriangleMesh readTriangleMesh(final Path path, final Precision.DoubleEquivalence precision) {
    437         return readTriangleMesh(new FileGeometryInput(path), null, precision);
    438     }
    439
    440     /** Return a {@link TriangleMesh} containing all triangles from the given URL. The data
    441      * format is determined from the file extension of the URL path. A runtime exception may be
    442      * thrown if mathematically invalid boundaries are encountered.
    443      * @param url URL to read from
    444      * @param precision precision context used for floating point comparisons
    445      * @return mesh containing all triangles from the given URL
    446      * @throws IllegalArgumentException if mathematically invalid data is encountered or no read handler
    447      *      is registered with the {@link #getDefaultManager() default manager} for the input format
    448      * @throws IllegalStateException if a data format error occurs
    449      * @throws java.io.UncheckedIOException if an I/O error occurs
    450      * @see BoundaryIOManager3D#readTriangleMesh(GeometryInput, GeometryFormat, Precision.DoubleEquivalence)
    451      */
    452     public static TriangleMesh readTriangleMesh(final URL url, final Precision.DoubleEquivalence precision) {
    453         return readTriangleMesh(new UrlGeometryInput(url), null, precision);
    454     }
    455
    456     /** Return a {@link TriangleMesh} containing all triangles from the given input. A runtime exception
    457      * may be thrown if mathematically invalid boundaries are encountered.
    458      * @param in input to read from
    459      * @param fmt format of the input; if null, the format is determined implicitly from the
    460      *      file extension of the input {@link GeometryInput#getFileName() file name}
    461      * @param precision precision context used for floating point comparisons
    462      * @return a mesh containing all triangles from the input
    463      * @throws IllegalArgumentException if mathematically invalid data is encountered or no read handler
    464      *      is registered with the {@link #getDefaultManager() default manager} for the input format
    465      * @throws IllegalStateException if a data format error occurs
    466      * @throws java.io.UncheckedIOException if an I/O error occurs
    467      * @see BoundaryIOManager3D#readTriangleMesh(GeometryInput, GeometryFormat, Precision.DoubleEquivalence)
    468      */
    469     public static TriangleMesh readTriangleMesh(final GeometryInput in, final GeometryFormat fmt,
    470             final Precision.DoubleEquivalence precision) {
    471         return getDefaultManager().readTriangleMesh(in, fmt, precision);
    472     }
    473
    474     /** Write all boundaries in the stream to given file path. The data format is determined by
    475      * the file extension of the target path. If the target path already exists, it is overwritten.
    476      *
    477      * <p>This method does not explicitly close the {@code boundaries} stream. Callers should use the stream
    478      * in a try-with-resources statement outside of this method if the stream is required to be closed.</p>
    479      * @param boundaries stream containing boundaries to write
    480      * @param path file path to write to
    481      * @throws IllegalArgumentException if no write handler is registered with the
    482      *      {@link #getDefaultManager() default manager} for the output format
    483      * @throws java.io.UncheckedIOException if an I/O error occurs
    484      * @see BoundaryIOManager3D#write(Stream, GeometryOutput, GeometryFormat)
    485      */
    486     public static void write(final Stream<? extends PlaneConvexSubset> boundaries, final Path path) {
    487         write(boundaries, new FileGeometryOutput(path), null);
    488     }
    489
    490     /** Write all boundaries in the stream to the output.
    491      *
    492      * <p>This method does not explicitly close the {@code boundaries} stream. Callers should use the stream
    493      * in a try-with-resources statement outside of this method if the stream is required to be closed.</p>
    494      * @param boundaries stream containing boundaries to write
    495      * @param out output to write to
    496      * @param fmt format of the output; if null, the format is determined implicitly from the
    497      *      file extension of the output {@link GeometryOutput#getFileName() file name}
    498      * @throws IllegalArgumentException if no write handler is registered with the
    499      *      {@link #getDefaultManager() default manager} for the output format
    500      * @throws java.io.UncheckedIOException if an I/O error occurs
    501      * @see BoundaryIOManager3D#write(Stream, GeometryOutput, GeometryFormat)
    502      */
    503     public static void write(final Stream<? extends PlaneConvexSubset> boundaries, final GeometryOutput out,
    504             final GeometryFormat fmt) {
    505         getDefaultManager().write(boundaries, out, fmt);
    506     }
    507
    508     /** Write all boundaries from {@code src} to the given file path. The data format
    509      * is determined by the file extension of the target path. If the target path already exists,
    510      * it is overwritten.
    511      * @param src boundary source containing the boundaries to write
    512      * @param path file path to write to
    513      * @throws IllegalArgumentException if no write handler is registered with the
    514      *      {@link #getDefaultManager() default manager} for the output format
    515      * @throws java.io.UncheckedIOException if an I/O error occurs
    516      * @see org.apache.commons.geometry.io.core.BoundaryIOManager#write(
    517      *      org.apache.commons.geometry.core.partitioning.BoundarySource, GeometryOutput, GeometryFormat)
    518      */
    519     public static void write(final BoundarySource3D src, final Path path) {
    520         write(src, new FileGeometryOutput(path), null);
    521     }
    522
    523     /** Write all boundaries from {@code src} to the given output.
    524      * @param src boundary source containing the boundaries to write
    525      * @param out output to write to
    526      * @param fmt format of the output; if null, the format is determined implicitly from the
    527      *      file extension of the output {@link GeometryOutput#getFileName() file name}
    528      * @throws IllegalArgumentException if no write handler is registered with the
    529      *      {@link #getDefaultManager() default manager} for the output format
    530      * @throws java.io.UncheckedIOException if an I/O error occurs
    531      * @see org.apache.commons.geometry.io.core.BoundaryIOManager#write(
    532      *      org.apache.commons.geometry.core.partitioning.BoundarySource, GeometryOutput, GeometryFormat)
    533      */
    534     public static void write(final BoundarySource3D src, final GeometryOutput out, final GeometryFormat fmt) {
    535         getDefaultManager().write(src, out, fmt);
    536     }
    537
    538     /** Write the given facets to the file path. The data format is determined by the file extension of
    539      * the target path. If the target path already exists, it is overwritten.
    540      * @param facets facets to write
    541      * @param path path to write to
    542      * @throws IllegalArgumentException if no write handler is registered with the
    543      *      {@link #getDefaultManager() default manager} for the output format
    544      * @throws java.io.UncheckedIOException if an I/O error occurs
    545      * @see BoundaryIOManager3D#writeFacets(Collection, GeometryOutput, GeometryFormat)
    546      */
    547     public static void writeFacets(final Collection<? extends FacetDefinition> facets, final Path path) {
    548         writeFacets(facets, new FileGeometryOutput(path), null);
    549     }
    550
    551     /** Write the given collection of facets to the output.
    552      * @param facets facets to write
    553      * @param out output to write to
    554      * @param fmt format of the output; if null, the format is determined implicitly from the
    555      *      file extension of the output {@link GeometryOutput#getFileName() file name}
    556      * @throws IllegalArgumentException if no write handler is registered with the
    557      *      {@link #getDefaultManager() default manager} for the output format
    558      * @throws java.io.UncheckedIOException if an I/O error occurs
    559      * @see BoundaryIOManager3D#writeFacets(Collection, GeometryOutput, GeometryFormat)
    560      */
    561     public static void writeFacets(final Collection<? extends FacetDefinition> facets, final GeometryOutput out,
    562             final GeometryFormat fmt) {
    563         getDefaultManager().writeFacets(facets, out, fmt);
    564     }
    565
    566     /** Write all facets in the stream to the file path. The data format is determined by the file
    567      * extension of the target path. If the target path already exists, it is overwritten.
    568      *
    569      * <p>This method does not explicitly close the {@code facets} stream. Callers should use the stream
    570      * in a try-with-resources statement outside of this method if the stream is required to be closed.</p>
    571      * @param facets stream containing facets to write
    572      * @param path path to write to
    573      * @throws IllegalArgumentException if no write handler is registered with the
    574      *      {@link #getDefaultManager() default manager} for the output format
    575      * @throws java.io.UncheckedIOException if an I/O error occurs
    576      * @see BoundaryIOManager3D#writeFacets(Stream, GeometryOutput, GeometryFormat)
    577      */
    578     public static void writeFacets(final Stream<? extends FacetDefinition> facets, final Path path) {
    579         writeFacets(facets, new FileGeometryOutput(path), null);
    580     }
    581
    582     /** Write all facets in the stream to the output.
    583      *
    584      * <p>This method does not explicitly close the {@code facets} stream. Callers should use the stream
    585      * in a try-with-resources statement outside of this method if the stream is required to be closed.</p>
    586      * @param facets stream containing facets to write
    587      * @param out output to write to
    588      * @param fmt format of the output; if null, the format is determined implicitly from the
    589      *      file extension of the output {@link GeometryOutput#getFileName() file name}
    590      * @throws IllegalArgumentException if no write handler is registered with the
    591      *      {@link #getDefaultManager() default manager} for the output format
    592      * @throws java.io.UncheckedIOException if an I/O error occurs
    593      * @see BoundaryIOManager3D#writeFacets(Stream, GeometryOutput, GeometryFormat)
    594      */
    595     public static void writeFacets(final Stream<? extends FacetDefinition> facets, final GeometryOutput out,
    596             final GeometryFormat fmt) {
    597         getDefaultManager().writeFacets(facets, out, fmt);
    598     }
    599
    600     /** Get the default {@link BoundaryIOManager3D} instance.
    601      * @return the default {@link BoundaryIOManager3D} instance
    602      */
    603     public static BoundaryIOManager3D getDefaultManager() {
    604         return ManagerHolder.DEFAULT_MANAGER;
    605     }
    606
    607     /** Class holding a reference to the default IO manager instance.
    608      */
    609     private static final class ManagerHolder {
    610
    611         /** Default IO manager instance. */
    612         private static final BoundaryIOManager3D DEFAULT_MANAGER;
    613
    614         static {
    615             DEFAULT_MANAGER = new BoundaryIOManager3D();
    616             DEFAULT_MANAGER.registerDefaultHandlers();
    617         }
    618
    619         /** Utility class; no instantiation. */
    620         private ManagerHolder() {}
    621     }
    622 }