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.ArrayList;
    20  import java.util.Iterator;
    21  import java.util.List;
    22  import java.util.NoSuchElementException;
    23  import java.util.Spliterator;
    24  import java.util.Spliterators;
    25  import java.util.stream.Stream;
    26  import java.util.stream.StreamSupport;
    27
    28  import org.apache.commons.geometry.euclidean.threed.BoundaryList3D;
    29  import org.apache.commons.geometry.euclidean.threed.BoundarySource3D;
    30  import org.apache.commons.geometry.euclidean.threed.PlaneConvexSubset;
    31  import org.apache.commons.geometry.euclidean.threed.Triangle3D;
    32  import org.apache.commons.geometry.euclidean.threed.mesh.SimpleTriangleMesh;
    33  import org.apache.commons.geometry.euclidean.threed.mesh.TriangleMesh;
    34  import org.apache.commons.geometry.io.core.input.GeometryInput;
    35  import org.apache.commons.geometry.io.core.internal.GeometryIOUtils;
    36  import org.apache.commons.numbers.core.Precision;
    37
    38  /** Abstract base class for {@link BoundaryReadHandler3D} implementations.
    39   */
    40  public abstract class AbstractBoundaryReadHandler3D implements BoundaryReadHandler3D {
    41
    42      /** {@inheritDoc} */
    43      @Override
    44      public BoundarySource3D read(final GeometryInput in, final Precision.DoubleEquivalence precision) {
    45          // read the input as a simple list of boundaries
    46          final List<PlaneConvexSubset> list = new ArrayList<>();
    47
    48          try (FacetDefinitionReader reader = facetDefinitionReader(in)) {
    49              FacetDefinition facet;
    50              while ((facet = reader.readFacet()) != null) {
    51                  list.add(FacetDefinitions.toPolygon(facet, precision));
    52              }
    53          }
    54
    55          return new BoundaryList3D(list);
    56      }
    57
    58      /** {@inheritDoc} */
    59      @Override
    60      public TriangleMesh readTriangleMesh(final GeometryInput in, final Precision.DoubleEquivalence precision) {
    61          final SimpleTriangleMesh.Builder meshBuilder = SimpleTriangleMesh.builder(precision);
    62
    63          try (FacetDefinitionReader reader = facetDefinitionReader(in)) {
    64              FacetDefinition facet;
    65              while ((facet = reader.readFacet()) != null) {
    66                  for (final Triangle3D tri : FacetDefinitions.toPolygon(facet, precision).toTriangles()) {
    67                      meshBuilder.addFaceUsingVertices(
    68                          tri.getPoint1(),
    69                          tri.getPoint2(),
    70                          tri.getPoint3()
    71                      );
    72                  }
    73              }
    74          }
    75
    76          return meshBuilder.build();
    77      }
    78
    79      /** {@inheritDoc} */
    80      @Override
    81      public Stream<PlaneConvexSubset> boundaries(final GeometryInput in, final Precision.DoubleEquivalence precision) {
    82          return facets(in)
    83                  .map(f -> FacetDefinitions.toPolygon(f, precision));
    84      }
    85
    86      /** {@inheritDoc} */
    87      @Override
    88      public Stream<FacetDefinition> facets(final GeometryInput in) {
    89          return GeometryIOUtils.createCloseableStream(inputStream -> {
    90              final FacetDefinitionReader fdReader = facetDefinitionReader(in);
    91              final FacetDefinitionReaderIterator it = new FacetDefinitionReaderIterator(fdReader);
    92
    93              return StreamSupport.stream(Spliterators.spliteratorUnknownSize(it, Spliterator.ORDERED), false);
    94          }, in::getInputStream);
    95      }
    96
    97      /** Class exposing a {@link FacetDefinitionReader} as an iterator.
    98       */
    99      static final class FacetDefinitionReaderIterator implements Iterator<FacetDefinition> {
    100
    101         /** Reader supplying the facets for iteration. */
    102         private final FacetDefinitionReader reader;
    103
    104         /** Number of facets read from the reader. */
    105         private int loadCount = 0;
    106
    107         /** Next facet to return from the instance; may be null. */
    108         private FacetDefinition next;
    109
    110         /** Construct a new iterator instance that iterates through the facets available from the
    111          * argument.
    112          * @param reader read supplying facets for iteration
    113          */
    114         FacetDefinitionReaderIterator(final FacetDefinitionReader reader) {
    115             this.reader = reader;
    116         }
    117
    118         /** {@inheritDoc} */
    119         @Override
    120         public boolean hasNext() {
    121             ensureLoaded();
    122             return next != null;
    123         }
    124
    125         /** {@inheritDoc} */
    126         @Override
    127         public FacetDefinition next() {
    128             if (!hasNext()) {
    129                 throw new NoSuchElementException();
    130             }
    131
    132             final FacetDefinition result = next;
    133             loadNext();
    134
    135             return result;
    136         }
    137
    138         /** Ensure that the instance has attempted to load at least one facet from
    139          * the underlying reader.
    140          */
    141         private void ensureLoaded() {
    142             if (loadCount < 1) {
    143                 loadNext();
    144             }
    145         }
    146
    147         /** Load the next facet from the underlying reader.
    148          */
    149         private void loadNext() {
    150             ++loadCount;
    151             next = reader.readFacet();
    152         }
    153     }
    154 }