AbstractBoundaryReadHandler3D.java

  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. import java.util.ArrayList;
  19. import java.util.Iterator;
  20. import java.util.List;
  21. import java.util.NoSuchElementException;
  22. import java.util.Spliterator;
  23. import java.util.Spliterators;
  24. import java.util.stream.Stream;
  25. import java.util.stream.StreamSupport;

  26. import org.apache.commons.geometry.euclidean.threed.BoundaryList3D;
  27. import org.apache.commons.geometry.euclidean.threed.BoundarySource3D;
  28. import org.apache.commons.geometry.euclidean.threed.PlaneConvexSubset;
  29. import org.apache.commons.geometry.euclidean.threed.Triangle3D;
  30. import org.apache.commons.geometry.euclidean.threed.mesh.SimpleTriangleMesh;
  31. import org.apache.commons.geometry.euclidean.threed.mesh.TriangleMesh;
  32. import org.apache.commons.geometry.io.core.input.GeometryInput;
  33. import org.apache.commons.geometry.io.core.internal.GeometryIOUtils;
  34. import org.apache.commons.numbers.core.Precision;

  35. /** Abstract base class for {@link BoundaryReadHandler3D} implementations.
  36.  */
  37. public abstract class AbstractBoundaryReadHandler3D implements BoundaryReadHandler3D {

  38.     /** {@inheritDoc} */
  39.     @Override
  40.     public BoundarySource3D read(final GeometryInput in, final Precision.DoubleEquivalence precision) {
  41.         // read the input as a simple list of boundaries
  42.         final List<PlaneConvexSubset> list = new ArrayList<>();

  43.         try (FacetDefinitionReader reader = facetDefinitionReader(in)) {
  44.             FacetDefinition facet;
  45.             while ((facet = reader.readFacet()) != null) {
  46.                 list.add(FacetDefinitions.toPolygon(facet, precision));
  47.             }
  48.         }

  49.         return new BoundaryList3D(list);
  50.     }

  51.     /** {@inheritDoc} */
  52.     @Override
  53.     public TriangleMesh readTriangleMesh(final GeometryInput in, final Precision.DoubleEquivalence precision) {
  54.         final SimpleTriangleMesh.Builder meshBuilder = SimpleTriangleMesh.builder(precision);

  55.         try (FacetDefinitionReader reader = facetDefinitionReader(in)) {
  56.             FacetDefinition facet;
  57.             while ((facet = reader.readFacet()) != null) {
  58.                 for (final Triangle3D tri : FacetDefinitions.toPolygon(facet, precision).toTriangles()) {
  59.                     meshBuilder.addFaceUsingVertices(
  60.                         tri.getPoint1(),
  61.                         tri.getPoint2(),
  62.                         tri.getPoint3()
  63.                     );
  64.                 }
  65.             }
  66.         }

  67.         return meshBuilder.build();
  68.     }

  69.     /** {@inheritDoc} */
  70.     @Override
  71.     public Stream<PlaneConvexSubset> boundaries(final GeometryInput in, final Precision.DoubleEquivalence precision) {
  72.         return facets(in)
  73.                 .map(f -> FacetDefinitions.toPolygon(f, precision));
  74.     }

  75.     /** {@inheritDoc} */
  76.     @Override
  77.     public Stream<FacetDefinition> facets(final GeometryInput in) {
  78.         return GeometryIOUtils.createCloseableStream(inputStream -> {
  79.             final FacetDefinitionReader fdReader = facetDefinitionReader(in);
  80.             final FacetDefinitionReaderIterator it = new FacetDefinitionReaderIterator(fdReader);

  81.             return StreamSupport.stream(Spliterators.spliteratorUnknownSize(it, Spliterator.ORDERED), false);
  82.         }, in::getInputStream);
  83.     }

  84.     /** Class exposing a {@link FacetDefinitionReader} as an iterator.
  85.      */
  86.     static final class FacetDefinitionReaderIterator implements Iterator<FacetDefinition> {

  87.         /** Reader supplying the facets for iteration. */
  88.         private final FacetDefinitionReader reader;

  89.         /** Number of facets read from the reader. */
  90.         private int loadCount = 0;

  91.         /** Next facet to return from the instance; may be null. */
  92.         private FacetDefinition next;

  93.         /** Construct a new iterator instance that iterates through the facets available from the
  94.          * argument.
  95.          * @param reader read supplying facets for iteration
  96.          */
  97.         FacetDefinitionReaderIterator(final FacetDefinitionReader reader) {
  98.             this.reader = reader;
  99.         }

  100.         /** {@inheritDoc} */
  101.         @Override
  102.         public boolean hasNext() {
  103.             ensureLoaded();
  104.             return next != null;
  105.         }

  106.         /** {@inheritDoc} */
  107.         @Override
  108.         public FacetDefinition next() {
  109.             if (!hasNext()) {
  110.                 throw new NoSuchElementException();
  111.             }

  112.             final FacetDefinition result = next;
  113.             loadNext();

  114.             return result;
  115.         }

  116.         /** Ensure that the instance has attempted to load at least one facet from
  117.          * the underlying reader.
  118.          */
  119.         private void ensureLoaded() {
  120.             if (loadCount < 1) {
  121.                 loadNext();
  122.             }
  123.         }

  124.         /** Load the next facet from the underlying reader.
  125.          */
  126.         private void loadNext() {
  127.             ++loadCount;
  128.             next = reader.readFacet();
  129.         }
  130.     }
  131. }