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.obj;
    18
    19  import java.nio.charset.Charset;
    20  import java.util.Iterator;
    21  import java.util.function.DoubleFunction;
    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.mesh.Mesh;
    27  import org.apache.commons.geometry.io.core.GeometryFormat;
    28  import org.apache.commons.geometry.io.core.internal.GeometryIOUtils;
    29  import org.apache.commons.geometry.io.core.output.GeometryOutput;
    30  import org.apache.commons.geometry.io.euclidean.threed.AbstractBoundaryWriteHandler3D;
    31  import org.apache.commons.geometry.io.euclidean.threed.FacetDefinition;
    32  import org.apache.commons.geometry.io.euclidean.threed.GeometryFormat3D;
    33
    34  /** {@link org.apache.commons.geometry.io.euclidean.threed.BoundaryWriteHandler3D BoundaryWriteHandler3D}
    35   * implementation for writing OBJ content. Output is written using the UTF-8 charset by default.
    36   */
    37  public class ObjBoundaryWriteHandler3D extends AbstractBoundaryWriteHandler3D {
    38
    39      /** The default line separator value. */
    40      private static final String DEFAULT_LINE_SEPARATOR = "\n";
    41
    42      /** Default mesh buffer batch size. */
    43      private static final int DEFAULT_MESH_BUFFER_BATCH_SIZE = -1;
    44
    45      /** Charset used for text output. */
    46      private Charset defaultCharset = ObjConstants.DEFAULT_CHARSET;
    47
    48      /** Line separator string. */
    49      private String lineSeparator = DEFAULT_LINE_SEPARATOR;
    50
    51      /** Double format function. */
    52      private DoubleFunction<String> doubleFormat = Double::toString;
    53
    54      /** Batch size used for mesh buffer creation. */
    55      private int meshBufferBatchSize = DEFAULT_MESH_BUFFER_BATCH_SIZE;
    56
    57      /** {@inheritDoc} */
    58      @Override
    59      public GeometryFormat getFormat() {
    60          return GeometryFormat3D.OBJ;
    61      }
    62
    63      /** Get the text output default charset, used if the output does not
    64       * specify a charset.
    65       * @return text output default charset
    66       */
    67      public Charset getDefaultCharset() {
    68          return defaultCharset;
    69      }
    70
    71      /** Set the text output default charset, used if the output does not
    72       * specify a charset.
    73       * @param charset text output default charset
    74       */
    75      public void setDefaultCharset(final Charset charset) {
    76          this.defaultCharset = charset;
    77      }
    78
    79      /** Get the line separator. This value defaults to {@value #DEFAULT_LINE_SEPARATOR}.
    80       * @return the current line separator
    81       */
    82      public String getLineSeparator() {
    83          return lineSeparator;
    84      }
    85
    86      /** Set the line separator.
    87       * @param lineSeparator the line separator to use
    88       */
    89      public void setLineSeparator(final String lineSeparator) {
    90          this.lineSeparator = lineSeparator;
    91      }
    92
    93      /** Get the function used to convert double values to strings.
    94       * @return double format function
    95       */
    96      public DoubleFunction<String> getDoubleFormat() {
    97          return doubleFormat;
    98      }
    99
    100     /** Set the function used to convert double values to strings. The given function
    101      * must be thread-safe if this handler is to be used in a multi-threaded context.
    102      * @param doubleFormat double format function
    103      */
    104     public void setDoubleFormat(final DoubleFunction<String> doubleFormat) {
    105         this.doubleFormat = doubleFormat;
    106     }
    107
    108     /** Get the batch size when generating OBJ mesh content from facet sequences. Larger batch sizes
    109      * allow for reuse of vertex definitions but at the cost of more memory usage. The buffer size is
    110      * unlimited if set to {@code -1}. Default value is {@value #DEFAULT_MESH_BUFFER_BATCH_SIZE}.
    111      * @return mesh buffer batch size
    112      * @see ObjWriter#meshBuffer(int)
    113      */
    114     public int getMeshBufferBatchSize() {
    115         return meshBufferBatchSize;
    116     }
    117
    118     /** Set the batch size when generating OBJ mesh content from facet sequences. Larger batch sizes
    119      * allow for reuse of vertex definitions but at the cost of more memory usage. Set to {@code -1}
    120      * to allow unlimited buffer size. Default value is {@value #DEFAULT_MESH_BUFFER_BATCH_SIZE}.
    121      * @param batchSize mesh buffer batch size; set to {@code -1} to allow unlimited buffer sizes
    122      * @see ObjWriter#meshBuffer(int)
    123      */
    124     public void setMeshBufferBatchSize(final int batchSize) {
    125         this.meshBufferBatchSize = batchSize;
    126     }
    127
    128     /** {@inheritDoc} */
    129     @Override
    130     public void write(final BoundarySource3D src, final GeometryOutput out) {
    131         // write meshes directly instead of iterating through boundaries
    132         if (src instanceof Mesh) {
    133             try (ObjWriter writer = createWriter(out)) {
    134                 writer.writeMesh((Mesh<?>) src);
    135             }
    136         } else {
    137             super.write(src, out);
    138         }
    139     }
    140
    141     /** {@inheritDoc} */
    142     @Override
    143     public void write(final Stream<? extends PlaneConvexSubset> boundaries, final GeometryOutput out) {
    144         try (ObjWriter writer = createWriter(out)) {
    145             final ObjWriter.MeshBuffer meshBuffer = writer.meshBuffer(meshBufferBatchSize);
    146
    147             final Iterator<? extends PlaneConvexSubset> it = boundaries.iterator();
    148             while (it.hasNext()) {
    149                 meshBuffer.add(it.next());
    150             }
    151
    152             meshBuffer.flush();
    153         }
    154     }
    155
    156     /** {@inheritDoc} */
    157     @Override
    158     public void writeFacets(final Stream<? extends FacetDefinition> facets, final GeometryOutput out) {
    159         try (ObjWriter writer = createWriter(out)) {
    160             final ObjWriter.MeshBuffer meshBuffer = writer.meshBuffer(meshBufferBatchSize);
    161
    162             final Iterator<? extends FacetDefinition> it = facets.iterator();
    163             while (it.hasNext()) {
    164                 meshBuffer.add(it.next());
    165             }
    166
    167             meshBuffer.flush();
    168         }
    169     }
    170
    171     /** Construct a new, configured {@link ObjWriter} instance for writing content to the given
    172      * output stream.
    173      * @param out output stream to write to
    174      * @return new {@code OBJWriter} for writing content to the given output stream
    175      * @throws java.io.UncheckedIOException if an I/O error occurs
    176      */
    177     private ObjWriter createWriter(final GeometryOutput out) {
    178         final ObjWriter writer = new ObjWriter(GeometryIOUtils.createBufferedWriter(out, defaultCharset));
    179         writer.setLineSeparator(lineSeparator);
    180         writer.setDoubleFormat(doubleFormat);
    181
    182         return writer;
    183     }
    184 }