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 }