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<FacetDefinition> 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<Triangle3D> 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 }