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.util.Collection;
    20  import java.util.stream.Stream;
    21
    22  import org.apache.commons.geometry.euclidean.threed.BoundarySource3D;
    23  import org.apache.commons.geometry.euclidean.threed.PlaneConvexSubset;
    24  import org.apache.commons.geometry.euclidean.threed.Triangle3D;
    25  import org.apache.commons.geometry.euclidean.threed.mesh.TriangleMesh;
    26  import org.apache.commons.geometry.io.core.BoundaryIOManager;
    27  import org.apache.commons.geometry.io.core.GeometryFormat;
    28  import org.apache.commons.geometry.io.core.input.GeometryInput;
    29  import org.apache.commons.geometry.io.core.output.GeometryOutput;
    30  import org.apache.commons.geometry.io.euclidean.threed.obj.ObjBoundaryReadHandler3D;
    31  import org.apache.commons.geometry.io.euclidean.threed.obj.ObjBoundaryWriteHandler3D;
    32  import org.apache.commons.geometry.io.euclidean.threed.stl.StlBoundaryReadHandler3D;
    33  import org.apache.commons.geometry.io.euclidean.threed.stl.StlBoundaryWriteHandler3D;
    34  import org.apache.commons.geometry.io.euclidean.threed.txt.CsvBoundaryReadHandler3D;
    35  import org.apache.commons.geometry.io.euclidean.threed.txt.CsvBoundaryWriteHandler3D;
    36  import org.apache.commons.geometry.io.euclidean.threed.txt.TextBoundaryReadHandler3D;
    37  import org.apache.commons.geometry.io.euclidean.threed.txt.TextBoundaryWriteHandler3D;
    38  import org.apache.commons.numbers.core.Precision;
    39
    40  /** Class managing IO operations for geometric data formats containing 3D region boundaries.
    41   * IO operation are performed by read and write handlers registered for specific data formats.
    42   *
    43   * <p><strong>Implementation note:</strong>Instances of this class are thread-safe as long as the
    44   * registered handler instances are thread-safe.</p>
    45   * @see BoundaryReadHandler3D
    46   * @see BoundaryWriteHandler3D
    47   * @see <a href="https://en.wikipedia.org/wiki/Boundary_representations">Boundary representations</a>
    48   */
    49  public class BoundaryIOManager3D extends BoundaryIOManager<
    50          PlaneConvexSubset,
    51          BoundarySource3D,
    52          BoundaryReadHandler3D,
    53          BoundaryWriteHandler3D> {
    54
    55      /** Get a {@link FacetDefinitionReader} for reading facet information from the given input.
    56       * @param in input to read facets from
    57       * @param fmt format of the input; if null, the format is determined implicitly from the
    58       *      file extension of the input {@link GeometryInput#getFileName() file name}
    59       * @return facet definition reader
    60       * @throws IllegalArgumentException if no read handler can be found for the input format
    61       * @throws IllegalStateException if a data format error occurs
    62       * @throws java.io.UncheckedIOException if an I/O error occurs
    63       */
    64      public FacetDefinitionReader facetDefinitionReader(final GeometryInput in, final GeometryFormat fmt) {
    65          return requireReadHandler(in, fmt).facetDefinitionReader(in);
    66      }
    67
    68      /** Return a {@link Stream} providing access to all facets from the given input. The underlying input
    69       * stream is closed when the returned stream is closed. Callers should therefore use the returned stream
    70       * in a try-with-resources statement to ensure that all resources are properly released.
    71       * <pre>
    72       *  try (Stream&lt;FacetDefinition&gt; stream = manager.facets(in, fmt)) {
    73       *      // access stream content
    74       *  }
    75       * </pre>
    76       * <p>The following exceptions may be thrown during stream iteration:</p>
    77       * <ul>
    78       *  <li>{@link IllegalStateException} if a data format error occurs</li>
    79       *  <li>{@link java.io.UncheckedIOException UncheckedIOException} if an I/O error occurs</li>
    80       * </ul>
    81       * @param in input to read from
    82       * @param fmt format of the input; if null, the format is determined implicitly from the
    83       *      file extension of the input {@link GeometryInput#getFileName() file name}
    84       * @return stream providing access to the facets in the input
    85       * @throws IllegalArgumentException if no read handler can be found for the input format
    86       * @throws IllegalStateException if a data format error occurs during stream creation
    87       * @throws java.io.UncheckedIOException if an I/O error occurs during stream creation
    88       */
    89      public Stream<FacetDefinition> facets(final GeometryInput in, final GeometryFormat fmt) {
    90          return requireReadHandler(in, fmt).facets(in);
    91      }
    92
    93      /** Return a {@link Stream} providing access to all triangles from the given input. The underlying input
    94       * stream is closed when the returned stream is closed. Callers should therefore use the returned stream
    95       * in a try-with-resources statement to ensure that all resources are properly released.
    96       * <pre>
    97       *  try (Stream&lt;Triangle3D&gt; stream = manager.triangles(in, fmt, precision)) {
    98       *      // access stream content
    99       *  }
    100      * </pre>
    101      * <p>The following exceptions may be thrown during stream iteration:</p>
    102      * <ul>
    103      *  <li>{@link IllegalArgumentException} if mathematically invalid data is encountered</li>
    104      *  <li>{@link IllegalStateException} if a data format error occurs</li>
    105      *  <li>{@link java.io.UncheckedIOException UncheckedIOException} if an I/O error occurs</li>
    106      * </ul>
    107      * @param in input to read from
    108      * @param fmt format of the input; if null, the format is determined implicitly from the
    109      *      file extension of the input {@link GeometryInput#getFileName() file name}
    110      * @param precision precision context used for floating point comparisons
    111      * @return stream providing access to the triangles in the input
    112      * @throws IllegalArgumentException if no read handler can be found for the input format
    113      * @throws IllegalStateException if a data format error occurs during stream creation
    114      * @throws java.io.UncheckedIOException if an I/O error occurs during stream creation
    115      */
    116     public Stream<Triangle3D> triangles(final GeometryInput in, final GeometryFormat fmt,
    117             final Precision.DoubleEquivalence precision) {
    118         return boundaries(in, fmt, precision)
    119                 .flatMap(p -> p.toTriangles().stream());
    120     }
    121
    122     /** Return a {@link TriangleMesh} containing all triangles from the given input.
    123      * @param in input to read from
    124      * @param fmt format of the input; if null, the format is determined implicitly from the
    125      *      file extension of the input {@link GeometryInput#getFileName() file name}
    126      * @param precision precision context used for floating point comparisons
    127      * @return mesh containing all triangles from the input
    128      * @throws IllegalArgumentException if mathematically invalid data is encountered or no read
    129      *      handler can be found for the input format
    130      * @throws IllegalStateException if a data format error occurs
    131      * @throws java.io.UncheckedIOException if an I/O error occurs
    132      */
    133     public TriangleMesh readTriangleMesh(final GeometryInput in, final GeometryFormat fmt,
    134             final Precision.DoubleEquivalence precision) {
    135         return requireReadHandler(in, fmt).readTriangleMesh(in, precision);
    136     }
    137
    138     /** Write all boundaries in the stream to the output.
    139      *
    140      * <p>This method does not explicitly close the {@code boundaries} stream. If callers need to ensure that
    141      * the stream is closed (for example, if the stream is reading from a file), they should use it in a
    142      * try-with-resources statement outside of this method.</p>
    143      * @param boundaries stream containing boundaries to write
    144      * @param out output to write to
    145      * @param fmt format of the output; if null, the format is determined implicitly from the
    146      *      file extension of the output {@link GeometryOutput#getFileName() file name}
    147      * @throws IllegalArgumentException if no write handler can be found for the output format
    148      * @throws java.io.UncheckedIOException if an I/O error occurs
    149      */
    150     public void write(final Stream<? extends PlaneConvexSubset> boundaries, final GeometryOutput out,
    151             final GeometryFormat fmt) {
    152         requireWriteHandler(out, fmt).write(boundaries, out);
    153     }
    154
    155     /** Write all facet in the stream to the output.
    156      *
    157      * <p>This method does not explicitly close the {@code boundaries} stream. If callers need to ensure that
    158      * the stream is closed (for example, if the stream is reading from a file), they should use it in a
    159      * try-with-resources statement outside of this method.</p>
    160      * @param facets stream containing facets to write
    161      * @param out output to write to
    162      * @param fmt format of the output; if null, the format is determined implicitly from the
    163      *      file extension of the output {@link GeometryOutput#getFileName() file name}
    164      * @throws IllegalArgumentException if no write handler can be found for the output format
    165      * @throws java.io.UncheckedIOException if an I/O error occurs
    166      */
    167     public void writeFacets(final Stream<? extends FacetDefinition> facets, final GeometryOutput out,
    168             final GeometryFormat fmt) {
    169         requireWriteHandler(out, fmt).writeFacets(facets, out);
    170     }
    171
    172     /** Write the given facets to the output.
    173      * @param facets facets to write
    174      * @param out output to write to
    175      * @param fmt format of the output; if null, the format is determined implicitly from the
    176      *      file extension of the output {@link GeometryOutput#getFileName() file name}
    177      * @throws IllegalArgumentException if no write handler can be found for the output format
    178      * @throws java.io.UncheckedIOException if an I/O error occurs
    179      */
    180     public void writeFacets(final Collection<? extends FacetDefinition> facets, final GeometryOutput out,
    181             final GeometryFormat fmt) {
    182         requireWriteHandler(out, fmt).writeFacets(facets, out);
    183     }
    184
    185     /** Register default read/write handlers. This method registers a read and write handler
    186      * for each value in {@link GeometryFormat3D}.
    187      */
    188     public void registerDefaultHandlers() {
    189         // obj
    190         registerReadHandler(new ObjBoundaryReadHandler3D());
    191         registerWriteHandler(new ObjBoundaryWriteHandler3D());
    192
    193         // stl
    194         registerReadHandler(new StlBoundaryReadHandler3D());
    195         registerWriteHandler(new StlBoundaryWriteHandler3D());
    196
    197         // txt
    198         registerReadHandler(new TextBoundaryReadHandler3D());
    199         registerWriteHandler(new TextBoundaryWriteHandler3D());
    200
    201         // csv
    202         registerReadHandler(new CsvBoundaryReadHandler3D());
    203         registerWriteHandler(new CsvBoundaryWriteHandler3D());
    204     }
    205 }