001/** 002 * CSTShapeFunction -- A generic CST Shape Function implementation. 003 * 004 * Copyright (C) 2014-2016, by Joseph A. Huwaldt. All rights reserved. 005 * 006 * This library is free software; you can redistribute it and/or modify it under the terms 007 * of the GNU Lesser General Public License as published by the Free Software Foundation; 008 * either version 2.1 of the License, or (at your option) any later version. 009 * 010 * This library is distributed in the hope that it will be useful, but WITHOUT ANY 011 * WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A 012 * PARTICULAR PURPOSE. See the GNU Library General Public License for more details. 013 * 014 * You should have received a copy of the GNU Lesser General Public License along with 015 * this program; if not, write to the Free Software Foundation, Inc., 59 Temple Place - 016 * Suite 330, Boston, MA 02111-1307, USA. Or visit: http://www.gnu.org/licenses/lgpl.html 017 */ 018package geomss.geom.cst; 019 020import geomss.geom.Point; 021import geomss.geom.Vector; 022import geomss.geom.nurbs.*; 023import java.util.List; 024import java.util.ResourceBundle; 025import javax.measure.quantity.Length; 026import javax.measure.unit.SI; 027import javolution.context.ArrayFactory; 028import javolution.context.ObjectFactory; 029import javolution.context.StackContext; 030import javolution.lang.ValueType; 031import javolution.util.FastTable; 032import javolution.xml.XMLFormat; 033import javolution.xml.XMLSerializable; 034import javolution.xml.stream.XMLStreamException; 035 036/** 037 * A generic Class-Shape-Transform (CST) shape function implementation. 038 * 039 * <p> Modified by: Joseph A. Huwaldt </p> 040 * 041 * @author Joseph A. Huwaldt Date: March 14, 2014 042 * @version January 8, 2016 043 */ 044@SuppressWarnings({"serial", "CloneableImplementsClone"}) 045public final class CSTShapeFunction implements Cloneable, XMLSerializable, ValueType { 046 // Reference: Kulfan, B.M., Bussoletti, J.E., "'Fundamental' Parametric Geometry 047 // Representations for Aircraft Component Shapes", AIAA-2006-6948. 048 /** 049 * The resource bundle for this package. 050 */ 051 private static final ResourceBundle RESOURCES = CSTCurve.RESOURCES; 052 053 private BasicNurbsCurve Scrv; 054 055 /** 056 * Construct a new shape function of the specified order from the specified list of 057 * Bernstein Polynomial coefficients. 058 * 059 * @param order The order of the shape function to return. 060 * @param Acoefs The coefficients of the Bernstein Polynomial used to construct the 061 * shape function. If more than "order" coefficients are provided then 062 * the additional coefficients are ignored. May not be null. 063 * @return A new shape function of the specified order from the specified list of 064 * Bernstein Polynomial coefficients. 065 */ 066 public static CSTShapeFunction newInstance(int order, double... Acoefs) { 067 if (Acoefs.length < order) 068 throw new IllegalArgumentException(RESOURCES.getString("orderNumCoefsErr")); 069 070 // Create a Bezier knot vector of the correct degree. 071 int degree = order - 1; 072 KnotVector kv = KnotVector.bezierKnotVector(degree); 073 074 // Turn the input coefficients into a list of 1D, unweighted, control points. 075 FastTable<ControlPoint> cpLst = FastTable.newInstance(); 076 for (int i = 0; i < order; ++i) { 077 double Ai = Acoefs[i]; 078 Point p = Point.valueOf(Ai, SI.METER); 079 ControlPoint cp = ControlPoint.valueOf(p, 1); 080 cpLst.add(cp); 081 } 082 083 // Create the defining Bezier curve. 084 BasicNurbsCurve Scrv = BasicNurbsCurve.newInstance(cpLst, kv); 085 FastTable.recycle(cpLst); 086 087 // Construct a new CSTShapeFunction and fill in the inputs. 088 CSTShapeFunction obj = FACTORY.object(); 089 obj.Scrv = Scrv; 090 091 return obj; 092 } 093 094 /** 095 * Construct a new shape function from the specified 1D basis function Bezier curve. 096 * 097 * @param bfCrv The 1D basis function Bezier curve used to define this shape function. 098 * May not be null. 099 * @return A new shape function based on the specified 1D basis function Bezier curve. 100 */ 101 public static CSTShapeFunction valueOf(NurbsCurve bfCrv) { 102 if (bfCrv.getPhyDimension() > 1) 103 throw new IllegalArgumentException(RESOURCES.getString("oneDCurve")); 104 105 FastTable<Double> pts = CurveUtils.getBezierStartParameters(bfCrv); 106 if (pts.size() > 2) 107 throw new IllegalArgumentException(RESOURCES.getString("singleBezierSegmentErr")); 108 FastTable.recycle(pts); 109 110 CSTShapeFunction obj = FACTORY.object(); 111 obj.Scrv = bfCrv.immutable().to(SI.METER); 112 113 return obj; 114 } 115 116 /** 117 * Return the order of this shape function. 118 * 119 * @return order of shape function (degree + 1) 120 * @see #getCoefficients() 121 */ 122 public int getOrder() { 123 return Scrv.getDegree() + 1; 124 } 125 126 /** 127 * Return the basis function for this shape function. The returned NURBS curve will 128 * always represent a 1D Bezier curve. 129 * @return The basis function for this shape function. 130 * @see #getCoefficients() 131 */ 132 public BasicNurbsCurve getBasisFunction() { 133 return Scrv; 134 } 135 136 /** 137 * Return the value of this shape function at the specified parametric location. 138 * 139 * @param s The parametric distance along the curve to calculate the value of this 140 * shape function at. 141 * @return The value of this shape function at the specified parametric location. 142 */ 143 public double getValue(double s) { 144 double S = Scrv.getRealPoint(s).getValue(Point.X); 145 return S; 146 } 147 148 /** 149 * Return a 2D point that represents the value of this shape function at the specified 150 * parametric position: (s,getValue(s)). 151 * 152 * @param s The parametric distance along the curve to calculate the value of this 153 * shape function at. 154 * @return A 2D point that represents the value of this shape function at the 155 * specified parametric position: P(s) = getValue(s). 156 */ 157 public Point get2DPoint(double s) { 158 Point p = Point.valueOf(s, getValue(s)); 159 return p; 160 } 161 162 /** 163 * Calculate all the derivatives from <code>0</code> to <code>grade</code> with 164 * respect to parametric distance on the shape function for the given parametric 165 * distance along the shape function, <code>d^{grade}p(s)/d^{grade}s</code>. 166 * <p> 167 * Example:<br> 168 * 1st derivative (grade = 1), this returns <code>[p(s), dp(s)/ds]</code>;<br> 169 * 2nd derivative (grade = 2), this returns <code>[p(s), dp(s)/ds, d^2p(s)/d^2s]</code>; etc. 170 * </p> 171 * 172 * @param s Parametric distance to calculate derivatives for (0.0 to 1.0 173 * inclusive). 174 * @param grade The maximum grade to calculate the derivatives for (1=1st derivative, 175 * 2=2nd derivative, etc) 176 * @return An array of derivatives up to the specified grade of the shape function at 177 * the specified parametric position. The returned array was allocated using 178 * javolution.context.ArrayFactory.DOUBLES_FACTORY, could be longer than the 179 * number of derivatives requested, and could be recycled by the user when no 180 * longer needed. 181 * @throws IllegalArgumentException if the grade is < 0. 182 */ 183 public double[] getDerivatives(double s, int grade) { 184 double[] output = ArrayFactory.DOUBLES_FACTORY.array(grade + 1); 185 186 StackContext.enter(); 187 try { 188 List<Vector<Length>> ders = Scrv.getSDerivatives(s, grade); 189 for (int i = grade; i >= 0; --i) 190 output[i] = ders.get(i).getValue(Point.X); 191 } finally { 192 StackContext.exit(); 193 } 194 195 return output; 196 } 197 198 /** 199 * Return the array of Bernstein Polynomial coefficients for this shape function. 200 * The array will have a length of the order of the polynomial. 201 * 202 * @return The array of Bernstein Polynomial coefficients for this shape function. 203 * @see #getOrder() 204 * @see #getBasisFunction() 205 */ 206 public double[] getCoefficients() { 207 List<ControlPoint> cps = Scrv.getControlPoints(); 208 int order = cps.size(); 209 double[] Acoef = new double[order]; 210 211 for (int i=0; i < order; ++i) { 212 ControlPoint cp = cps.get(i); 213 Point p = cp.getPoint(); 214 Acoef[i] = p.getValue(Point.X); 215 } 216 217 FastTable.recycle((FastTable)cps); 218 219 return Acoef; 220 } 221 222 /** 223 * Return <code>true</code> if this shape function contains valid and finite numerical 224 * components. A value of <code>false</code> will be returned if any of the values are 225 * NaN or Inf. 226 * 227 * @return true if this shape function contains valid and finite numerical values. 228 */ 229 public boolean isValid() { 230 return Scrv.isValid(); 231 } 232 233 /** 234 * Compares this CSTShapeFunction against the specified object for strict equality 235 * (same values). 236 * 237 * @param obj the object to compare with. 238 * @return <code>true</code> if this object is identical to that object; 239 * <code>false</code> otherwise. 240 */ 241 @Override 242 public boolean equals(Object obj) { 243 if (this == obj) 244 return true; 245 if ((obj == null) || (obj.getClass() != this.getClass())) 246 return false; 247 248 CSTShapeFunction that = (CSTShapeFunction)obj; 249 return this.Scrv.equals(that.Scrv); 250 } 251 252 /** 253 * Returns the hash code for this object. 254 * 255 * @return the hash code value. 256 */ 257 @Override 258 public int hashCode() { 259 int hash = 7; 260 261 hash = hash * 31 + Scrv.hashCode(); 262 263 return hash; 264 } 265 266 /** 267 * Returns a copy of this CSTShapeFunction instance 268 * {@link javolution.context.AllocatorContext allocated} by the calling thread 269 * (possibly on the stack). 270 * 271 * @return an identical and independent copy of this object. 272 */ 273 @Override 274 public CSTShapeFunction copy() { 275 return copyOf(this); 276 } 277 278 /** 279 * Holds the default XML representation for this object. 280 */ 281 protected static final XMLFormat<CSTShapeFunction> XML = new XMLFormat<CSTShapeFunction>(CSTShapeFunction.class) { 282 @Override 283 public CSTShapeFunction newInstance(Class<CSTShapeFunction> cls, XMLFormat.InputElement xml) throws XMLStreamException { 284 return FACTORY.object(); 285 } 286 287 @Override 288 public void read(XMLFormat.InputElement xml, CSTShapeFunction obj) throws XMLStreamException { 289 BasicNurbsCurve Scrv = xml.getNext(); 290 obj.Scrv = Scrv; 291 } 292 293 @Override 294 public void write(CSTShapeFunction obj, XMLFormat.OutputElement xml) throws XMLStreamException { 295 xml.add(obj.Scrv); 296 } 297 }; 298 299 /////////////////////// 300 // Factory creation. // 301 /////////////////////// 302 private CSTShapeFunction() { } 303 304 @SuppressWarnings("unchecked") 305 private static final ObjectFactory<CSTShapeFunction> FACTORY = new ObjectFactory<CSTShapeFunction>() { 306 @Override 307 protected CSTShapeFunction create() { 308 return new CSTShapeFunction(); 309 } 310 311 @Override 312 protected void cleanup(CSTShapeFunction obj) { 313 obj.Scrv = null; 314 } 315 }; 316 317 @SuppressWarnings("unchecked") 318 private static CSTShapeFunction copyOf(CSTShapeFunction original) { 319 CSTShapeFunction obj = FACTORY.object(); 320 obj.Scrv = original.Scrv.copy(); 321 return obj; 322 } 323}