001/* 002 * GeomTriangle -- Represents an abstract planar triangle in n-D space. 003 * 004 * Copyright (C) 2015-2016, Joseph A. Huwaldt 005 * All rights reserved. 006 * 007 * This library is free software; you can redistribute it and/or 008 * modify it under the terms of the GNU Lesser General Public 009 * License as published by the Free Software Foundation; either 010 * version 2.1 of the License, or (at your option) any later version. 011 * 012 * This library is distributed in the hope that it will be useful, 013 * but WITHOUT ANY WARRANTY; without even the implied warranty of 014 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 015 * Lesser General Public License for more details. 016 * 017 * You should have received a copy of the GNU Lesser General Public License 018 * along with this program; if not, write to the Free Software 019 * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. 020 * Or visit: http://www.gnu.org/licenses/lgpl.html 021 */ 022package geomss.geom; 023 024import static geomss.geom.AbstractGeomElement.RESOURCES; 025import jahuwaldt.js.param.Parameter; 026import java.text.MessageFormat; 027import static java.util.Objects.nonNull; 028import javax.measure.quantity.Area; 029import javax.measure.quantity.Dimensionless; 030import javax.measure.quantity.Length; 031import javax.measure.unit.Unit; 032import javolution.text.Text; 033import javolution.text.TextBuilder; 034 035/** 036 * The interface and implementation in common to all triangles in n-dimensional space. A 037 * triangle is represented by exactly three vertex points arranged in a counter-clockwise 038 * direction (or winding) when viewed from the "outside" (the direction the normal vector 039 * points). 040 * 041 * <p> Modified by: Joseph A. Huwaldt </p> 042 * 043 * @author Joseph A. Huwaldt, Date: August 26, 2015 044 * @version February 16, 2016 045 */ 046@SuppressWarnings({"serial", "CloneableImplementsClone"}) 047public abstract class GeomTriangle extends AbstractGeomElement<GeomTriangle> 048 implements PointGeometry<GeomTriangle>, Transformable<GeomTriangle> { 049 050 /** 051 * A flag indicating if this triangle is degenerate or not. A value of -1 means 052 * degeneracy has not been assessed. A value of 0 means the triangle is NOT 053 * degenerate. A value of 1 means that the triangle IS degenerate. 054 */ 055 private int _degFlg = -1; 056 057 058 /** 059 * Return the first vertex in this triangle. 060 * 061 * @return The first vertex in this triangle. 062 */ 063 public abstract GeomPoint getP1(); 064 065 /** 066 * Return the second vertex in this triangle. 067 * 068 * @return The second vertex in this triangle. 069 */ 070 public abstract GeomPoint getP2(); 071 072 /** 073 * Return the third and last vertex in this triangle. 074 * 075 * @return The third and last vertex in this triangle. 076 */ 077 public abstract GeomPoint getP3(); 078 079 /** 080 * Return the surface unit normal vector for this triangle. If the triangle is 081 * degenerate (zero area), then the normal vector will have zero length. 082 * 083 * @return The surface normal vector for this triangle. 084 */ 085 public abstract GeomVector<Dimensionless> getNormal(); 086 087 /** 088 * Return the surface area of one side of this triangle. The returned area is always 089 * positive, but can be zero. 090 * 091 * @return The surface area of one side of this triangle. 092 */ 093 public abstract Parameter<Area> getArea(); 094 095 /** 096 * Return <code>true</code> if this triangle is degenerate (i.e.: has zero surface 097 * area). A degenerate triangle is defined as a triangle that has any edge with length 098 * less than the input tolerance. 099 * 100 * @param tol The tolerance for determining if this triangle is degenerate. A value of 101 * <code>null</code> would indicate that exactly zero area is required to 102 * be degenerate. 103 * @return true if this triangle is degenerate. 104 */ 105 public boolean isDegenerate(Parameter<Length> tol) { 106 if (_degFlg < 0) { 107 GeomPoint p1 = getP1(); 108 GeomPoint p2 = getP2(); 109 if (p1.isApproxEqual(p2, tol)) { 110 _degFlg = 1; 111 return true; 112 } 113 GeomPoint p3 = getP3(); 114 boolean output = p1.isApproxEqual(p3,tol) || p2.isApproxEqual(p3,tol); 115 _degFlg = (output ? 1 : 0); 116 return output; 117 } 118 return _degFlg > 0; 119 } 120 121 /** 122 * Return a new triangle that is identical to this one, but with the order of the 123 * points (and the surface normal direction) reversed. 124 * 125 * @return A new Triangle that is identical to this one, but with the order of the 126 * points reversed. 127 */ 128 public abstract GeomTriangle reverse(); 129 130 /** 131 * Return all three vertices of this triangle as an ordered list of points. 132 * 133 * @return A list containing the three vertices of this triangle in counter-clockwise 134 * order. 135 */ 136 public PointString<? extends GeomPoint> getPoints() { 137 GeomPoint p1 = getP1(); 138 GeomPoint p2 = getP2(); 139 GeomPoint p3 = getP3(); 140 PointString<? extends GeomPoint> str = PointString.valueOf(p1, p2, p3); 141 return str; 142 } 143 144 /** 145 * Return all three vertices of this triangle contained in the supplied array of 146 * points. The input array must have at least 3 elements. 147 * 148 * @param points An existing array with at leat 3 elements that will be filled in with 149 * points from this triangle. May not be null. 150 * @return The input array with the three vertices of this triangle, in counter- 151 * clockwise order, placed in the 1st 3 elements. 152 */ 153 public GeomPoint[] getPoints(GeomPoint[] points) { 154 points[0] = getP1(); 155 points[1] = getP2(); 156 points[2] = getP3(); 157 return points; 158 } 159 160 /** 161 * Returns an new {@link GeomList} containing the ordered points in this triangle. 162 * 163 * @return A new GeomList containing the ordered points from this triangle. 164 */ 165 public GeomList<GeomPoint> getAll() { 166 GeomList<GeomPoint> list = GeomList.newInstance(); 167 list.add(getP1()); 168 list.add(getP2()); 169 list.add(getP3()); 170 return list; 171 } 172 173 /** 174 * Returns the number of child-elements that make up this geometry element. This 175 implementation always returns 3 as a GeomTriangle has three vertices. 176 * 177 * @return The number of points in this triangle (always returns 3). 178 */ 179 @Override 180 public int size() { 181 return 3; 182 } 183 184 /** 185 * Returns the number of physical dimensions of the geometry element. 186 * 187 * @return The number of physical dimensions of this geometry element. 188 */ 189 @Override 190 public int getPhyDimension() { 191 return getP1().getPhyDimension(); 192 } 193 194 /** 195 * Returns the number of parametric dimensions of the geometry element. This 196 * implementation always returns 0 as a Triangle is not parametric. 197 */ 198 @Override 199 public int getParDimension() { 200 return 0; 201 } 202 203 /** 204 * Return the total number of points in this geometry element. This implementation 205 * always returns 3 as a GeomTriangle has three vertices. 206 * 207 * @return Always returns 3. 208 */ 209 @Override 210 public int getNumberOfPoints() { 211 return 3; 212 } 213 214 /** 215 * Returns the most extreme point, either minimum or maximum, in the specified 216 * coordinate direction on this triangle. 217 * 218 * @param dim An index indicating the dimension to find the min/max point for (0=X, 219 * 1=Y, 2=Z, etc). 220 * @param max Set to <code>true</code> to return the maximum value, <code>false</code> 221 * to return the minimum. 222 * @param tol Fractional tolerance (in parameter space) to refine the min/max point 223 * position to. 224 * @return The point found on this triangle that is the min or max in the specified 225 * coordinate direction. 226 */ 227 @Override 228 public GeomPoint getLimitPoint(int dim, boolean max, double tol) { 229 // Check the input dimension for consistancy. 230 int thisDim = getPhyDimension(); 231 if (dim < 0 || dim >= thisDim) 232 throw new DimensionException(MessageFormat.format( 233 RESOURCES.getString("inputDimOutOfRange"), "triangle")); 234 235 // Get the three points. 236 PointString str = getPoints(); 237 238 // Return the limit of the three points. 239 return str.getLimitPoint(dim, max, tol); 240 } 241 242 /** 243 * Return <code>true</code> if this GeomTriangle contains valid and finite numerical 244 * components. A value of <code>false</code> will be returned if any of the coordinate 245 * values are NaN or Inf. 246 * 247 * @return true if this GeomTriangle contains valid and finite data. 248 */ 249 @Override 250 public boolean isValid() { 251 return getP1().isValid() && getP2().isValid() && getP3().isValid(); 252 } 253 254 /** 255 * Returns the unit in which this GeomTriangle is stated. 256 * 257 * @return The unit in which this GeomTriangle is stated. 258 */ 259 @Override 260 public Unit<Length> getUnit() { 261 return getP1().getUnit(); 262 } 263 264 /** 265 * Returns the text representation of this geometry element that consists of the name 266 * followed by the three defining points. For example: 267 * <pre> 268 * {aTri = {{0.0 m, 0.0 m},{1.0 m, 0.0 m},{0.5 m, 1.0 m}} 269 * </pre> 270 * If there is no name, then the output looks like this: 271 * <pre> 272 * {{0.0 m, 0.0 m},{1.0 m, 0.0 m},{0.5 m, 1.0 m}} 273 * </pre> 274 * 275 * @return the text representation of this geometry element. 276 */ 277 @Override 278 public Text toText() { 279 TextBuilder tmp = TextBuilder.newInstance(); 280 tmp.append('{'); 281 String nameStr = getName(); 282 boolean hasName = nonNull(nameStr); 283 if (hasName) { 284 tmp.append(nameStr); 285 tmp.append(" = {"); 286 } 287 288 tmp.append(getP1().toText()); 289 tmp.append(","); 290 tmp.append(getP2().toText()); 291 tmp.append(","); 292 tmp.append(getP3().toText()); 293 294 if (hasName) 295 tmp.append('}'); 296 tmp.append('}'); 297 Text txt = tmp.toText(); 298 TextBuilder.recycle(tmp); 299 return txt; 300 } 301 302 /** 303 * Resets the internal state of this object to its default values. Subclasses that 304 * override this method must call <code>super.reset();</code> to ensure that the state 305 * is reset properly. 306 */ 307 @Override 308 public void reset() { 309 super.reset(); 310 this._degFlg = -1; 311 } 312 313}