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.stl;
18  
19  import java.nio.ByteBuffer;
20  
21  import org.apache.commons.geometry.euclidean.threed.Vector3D;
22  
23  /** Utility methods for the STL format.
24   */
25  final class StlUtils {
26  
27      /** Utility class; no instantiation. */
28      private StlUtils() { }
29  
30      /** Create a {@link ByteBuffer} with the given size and the byte order
31       * appropriate for binary STL content.
32       * @param capacity buffer capacity
33       * @return byte buffer
34       */
35      static ByteBuffer byteBuffer(final int capacity) {
36          return ByteBuffer.allocate(capacity)
37                  .order(StlConstants.BINARY_BYTE_ORDER);
38      }
39  
40      /** Determine the normal that should be used for the given STL triangle vertices. If {@code normal}
41       * is present and can be normalized, it is returned. Otherwise, a normal is attempted to be computed
42       * using the given triangle vertices. If normal computation fails, the zero vector is returned.
43       * @param p1 first point
44       * @param p2 second point
45       * @param p3 third point
46       * @param normal defined triangle normal; may be null
47       * @return STL normal for the triangle
48       */
49      static Vector3D determineNormal(final Vector3D p1, final Vector3D p2, final Vector3D p3,
50              final Vector3D normal) {
51          if (normal != null) {
52              // try to normalize it
53              final Vector3D normalized = normal.normalizeOrNull();
54              if (normalized != null) {
55                  return normalized;
56              }
57          }
58  
59          // try to compute one from the triangle points
60          final Vector3D computed = computeTriangleNormal(p1, p2, p3);
61          return computed != null ?
62                  computed :
63                  Vector3D.ZERO;
64      }
65  
66      /** Return true if the given points are arranged counter-clockwise relative to the
67       * given normal. Returns true if {@code normal} is null.
68       * @param p1 first point
69       * @param p2 second point
70       * @param p3 third point
71       * @param normal normal; may be null, in which case the zero vector is used
72       * @return true if {@code normal} is null or if the given points are arranged counter-clockwise
73       *      relative to {@code normal}
74       */
75      static boolean pointsAreCounterClockwise(final Vector3D p1, final Vector3D p2, final Vector3D p3,
76              final Vector3D normal) {
77          if (normal != null) {
78              final Vector3D computedNormal = computeTriangleNormal(p1, p2, p3);
79              if (computedNormal != null && normal.dot(computedNormal) < 0) {
80                  return false;
81              }
82          }
83  
84          return true;
85      }
86  
87      /** Get the normal using the right-hand rule for the given triangle vertices. Null is returned
88       * if the normal could not be computed.
89       * @param p1 first point
90       * @param p2 second point
91       * @param p3 third point
92       * @return the normal for the given triangle vertices or null if one could not be computed
93       */
94      private static Vector3D computeTriangleNormal(final Vector3D p1, final Vector3D p2, final Vector3D p3) {
95          final Vector3D normal = p1.vectorTo(p2).cross(p1.vectorTo(p3)).normalizeOrNull();
96          return normal != null ?
97                  normal :
98                  null;
99      }
100 }