001/* 002 * Entity104_ConicArc -- Entity representing a general conic section other than a circle. 003 * 004 * Copyright (C) 2010-2016, Joseph A. Huwaldt. All rights reserved. 005 * 006 * This library is free software; you can redistribute it and/or 007 * modify it under the terms of the GNU Lesser General Public 008 * License as published by the Free Software Foundation; either 009 * version 2.1 of the License, or (at your option) any later version. 010 * 011 * This library is distributed in the hope that it will be useful, 012 * but WITHOUT ANY WARRANTY; without even the implied warranty of 013 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 014 * Lesser General Public License for more details. 015 * 016 * You should have received a copy of the GNU Lesser General Public License 017 * along with this program; if not, write to the Free Software 018 * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. 019 * Or visit: http://www.gnu.org/licenses/lgpl.html 020 * 021 * Based on, but heavily modified from, IGESView ( http://ts.nist.gov/Standards/IGES/igesTools.cfm ) 022 */ 023package geomss.geom.reader.iges; 024 025import geomss.geom.*; 026import geomss.geom.nurbs.*; 027import jahuwaldt.js.param.Parameter; 028import java.io.IOException; 029import java.io.RandomAccessFile; 030import java.text.MessageFormat; 031import javax.measure.quantity.Angle; 032import javax.measure.quantity.Dimensionless; 033import javax.measure.quantity.Length; 034import javax.measure.unit.SI; 035import static javolution.lang.MathLib.*; 036import javolution.util.FastTable; 037 038/** 039 * <b><i>CONIC ARC ENTITY</i></b> - This entity defines an ellipse, a parabola, a 040 * hyperbola, or a portion of one of these conic curves which may be isolated or used as a 041 * component of a Composite Curve or a sub-figure. The definition space coordinate system 042 * is always chosen so that the conic arc lies in a plane either coincident with or 043 * parallel to XT, YT plane. Within such a plane a conic is defined by the six 044 * coefficients in the following equation: A*XT^2 + B*XT*YT + C*YT^2 + D*XT + E*YT + F = 0 045 * 046 * <p> 047 * These entities (forms 0-3), when read from an IGES file, are converted to NURBS curves 048 * of degree 2 (IGES type 126, Form 2, Degree 2). This entity type can not be written out 049 * to an IGES file. All conic arc parameters are stored in the user data with the prefix 050 * "IGES_106_" followed by the parameter name. 051 * </p> 052 * 053 * <p> Modified by: Joseph A. Huwaldt </p> 054 * 055 * @author JDN, Version 1.0 056 * @version September 13, 2016 057 */ 058public abstract class Entity104_ConicArc extends GeomSSEntity { 059 060 private double Acoef; // General Conic Coefficients 061 private double Bcoef; 062 private double Ccoef; 063 private double Dcoef; 064 private double Ecoef; 065 private double Fcoef; 066 private double zt; // ZT Coordinate of plane of definition 067 private double x1; // Start point abcissa 068 private double y1; // Start point ordinate 069 private double x2; // Terminate point abcissa 070 private double y2; // Terminate point ordinate 071 072 private double Q1, Q2; // Used to determine conic type. 073 074 private NurbsCurve curve; // THe GeomSS curve representing this conic section. 075 076 /** 077 * Default constructor. 078 * 079 * @param p part to which this entity is contained 080 * @param de Directory Entry for this entity 081 */ 082 public Entity104_ConicArc(Part p, DirEntry de) { 083 super(p, de); 084 } 085 086 /** 087 * Checks to see if the entity should be drawn. No restrictions are imposed. 088 */ 089 @Override 090 public void check() { 091 } 092 093 /** 094 * Read the Parameter Data from the String read in by the superclass. 095 * 096 * @param in input file 097 * @throws java.io.IOException 098 */ 099 @Override 100 public void read(RandomAccessFile in) throws IOException { 101 super.read(in); 102 String s = getPDString(); 103 104 if (Constants.DEBUG) { 105 System.out.println("PD String = \"" + s + "\""); 106 } 107 108 Acoef = getReal(s); 109 Bcoef = getReal(s); 110 Ccoef = getReal(s); 111 Dcoef = getReal(s); 112 Ecoef = getReal(s); 113 Fcoef = getReal(s); 114 zt = getReal(s); 115 if (Math.abs(zt) < Constants.Grain) 116 zt = 0; 117 x1 = getReal(s); 118 if (Math.abs(x1) < Constants.Grain) 119 x1 = 0; 120 y1 = getReal(s); 121 if (Math.abs(y1) < Constants.Grain) 122 y1 = 0; 123 x2 = getReal(s); 124 if (Math.abs(x2) < Constants.Grain) 125 x2 = 0; 126 y2 = getReal(s); 127 if (Math.abs(y2) < Constants.Grain) 128 y2 = 0; 129 130 if (abs(Bcoef) > Constants.Grain || Acoef > Ccoef) 131 throw new IOException( 132 MessageFormat.format(RESOURCES.getString("rotatedConicsNotSupported"), 133 getHeader())); 134 135 super.read_additional(); 136 137 // Calculate some needed parameters. 138 double A = Acoef, B = Bcoef, C = Ccoef, D = Dcoef, E = Ecoef, F = Fcoef; 139 Q1 = A * C * F + 0.25 * (B * D * E - A * E * E - B * B * F - D * D * C); 140 Q2 = A * C - 0.25 * B * B; 141 142 } 143 144 /** 145 * The GeomSS geometry element is created from the IGES parameters when this method is 146 * called. 147 */ 148 @Override 149 void createGeometry() throws IOException { 150 151 // Determine the curve type (do not trust the form ID). 152 if (abs(Q2) < Constants.Grain && abs(Q1) >= Constants.Grain) { 153 // Parabola 154 curve = makeParabolicCurve(); 155 156 } else if (Q2 < 0 && abs(Q1) >= Constants.Grain) { 157 // Hyperbola 158 curve = makeHyperbolicCurve(); 159 160 } else if (Q2 > 0 && Q1 * (Acoef + Ccoef) < 0) { 161 // Ellipse 162 curve = makeEllipseCurve(); 163 164 } else { 165 System.out.println(toString()); 166 System.out.println("Q1 = " + Q1 + ", Q2 = " + Q2); 167 168 throw new IOException(MessageFormat.format(RESOURCES.getString("unknownConicType"), getHeader())); 169 } 170 171 } 172 173 /** 174 * Method used to apply IGES meta-data to GeomSS elements. This implementation stores 175 * in the user data, in addition to the header info, all the parameter information for 176 * this entity type prefixed by "IGES_104_". 177 */ 178 @Override 179 protected void applyMetaData(GeomElement element) { 180 super.applyMetaData(element); 181 element.putUserData("IGES_104_A", Acoef); 182 element.putUserData("IGES_104_B", Bcoef); 183 element.putUserData("IGES_104_C", Ccoef); 184 element.putUserData("IGES_104_D", Dcoef); 185 element.putUserData("IGES_104_E", Ecoef); 186 element.putUserData("IGES_104_F", Fcoef); 187 element.putUserData("IGES_104_ZT", zt); 188 element.putUserData("IGES_104_X1", x1); 189 element.putUserData("IGES_104_Y1", y1); 190 element.putUserData("IGES_104_X2", x2); 191 element.putUserData("IGES_104_Y2", y2); 192 } 193 194 /** 195 * Return a new elliptical arc segment based on the general conic equation 196 * coefficients and end points. 197 */ 198 private BasicNurbsCurve makeEllipseCurve() { 199 // Determine semi-major and semi-minor axis lengths. 200 Parameter<Length> sma = Parameter.valueOf(sqrt(-Fcoef / Acoef), Constants.unit); 201 Parameter<Length> smb = Parameter.valueOf(sqrt(-Fcoef / Ccoef), Constants.unit); 202 203 // Determine the origin of the ellipse. 204 double xo = -2 * Ccoef * Dcoef / 4 / Q1; 205 double yo = -2 * Acoef * Ecoef / 4 / Q1; 206 Point origin = Point.valueOf(xo, yo, zt, Constants.unit); 207 208 // Determine the start and ending angles. 209 double p1mOx = x1 - xo; 210 double p1mOy = y1 - yo; 211 double p2mOx = x2 - xo; 212 double p2mOy = y2 - yo; 213 double ths = atan2(p1mOy, p1mOx); 214 double the = atan2(p2mOy, p2mOx); 215 Parameter<Angle> thetaStart = Parameter.valueOf(ths, SI.RADIAN); 216 Parameter<Angle> thetaEnd = Parameter.valueOf(the, SI.RADIAN); 217 218 // Define X & Y directions. 219 Vector<Dimensionless> xhat = Vector.valueOf(1, 0, 0).toUnitVector(); 220 Vector<Dimensionless> yhat = Vector.valueOf(0, 1, 0).toUnitVector(); 221 222 // Create the elliptical arc. 223 return CurveFactory.createEllipticalArc(origin, sma, smb, xhat, yhat, thetaStart, thetaEnd); 224 } 225 226 /** 227 * Return a new hyperbolic arc segment based on the general conic equation 228 * coefficients and end points. 229 */ 230 private BasicNurbsCurve makeHyperbolicCurve() { 231 Parameter<Length> tol = Parameter.valueOf(Constants.Grain, Constants.unit); 232 233 // Create end points. 234 Point p0 = Point.valueOf(x1, y1, zt, Constants.unit); 235 Point p2 = Point.valueOf(x2, y2, zt, Constants.unit); 236 237 // Create tangent vectors at each end. 238 Vector t0 = derivative(x1, y1); 239 Vector t2 = derivative(x2, y2); 240 241 // Find the intersection of the two tangent vector lines. 242 MutablePoint p1 = MutablePoint.newInstance(3, Constants.unit); 243 GeomUtil.lineLineIntersect(p0, t0, p2, t2, tol, null, p1, null); 244 245 // Find the bisector of the line between the end points. 246 GeomPoint pM = p0.plus(p2).divide(2); 247 248 // Find the shoulder point on the curve. 249 Point S; 250 double xm = pM.getValue(0); 251 double xp1 = p1.getValue(0); 252 double A = Acoef, C = Ccoef, F = Fcoef; 253 if (abs(xm - xp1) < Constants.Grain) { 254 // Line from m to p1 is vertical. 255 double ys = sqrt(-C * (A * xm * xm + F)) / C; 256 S = Point.valueOf(xm, ys, zt, Constants.unit); 257 258 } else { 259 double yp1 = p1.getValue(1); 260 double ym = pM.getValue(1); 261 double m = (ym - yp1) / (xm - xp1); 262 double b = yp1 - m * xp1; 263 double den = 2 * (A + C * m * m); 264 265 double xs = -2 * C * m * b + 2 * sqrt(-A * F - A * C * b * b - C * F * m * m); 266 xs /= den; 267 double ys = m * xs + b; 268 269 S = Point.valueOf(xs, ys, zt, Constants.unit); 270 } 271 272 // Determine the weight of the middle control point. 273 double w1 = pM.distance(S).divide(S.distance(p1)).getValue(); 274 275 // Create the control points. 276 FastTable<ControlPoint> cps = FastTable.newInstance(); 277 cps.add(ControlPoint.valueOf(p0, 1)); 278 cps.add(ControlPoint.valueOf(p1.immutable(), w1)); 279 cps.add(ControlPoint.valueOf(p2, 1)); 280 MutablePoint.recycle(p1); 281 282 // Create the knot vector. 283 KnotVector kv = KnotVector.newInstance(2, 0., 0., 0., 1., 1., 1.); 284 285 // Create the curve. 286 BasicNurbsCurve crv = BasicNurbsCurve.newInstance(cps, kv); 287 288 // Clean up before leaving. 289 FastTable.recycle(cps); 290 291 return crv; 292 } 293 294 /** 295 * Return a new parabolic arc segment based on the general conic equation coefficients 296 * and end points. 297 */ 298 private BasicNurbsCurve makeParabolicCurve() { 299 // Create end points. 300 Point p1 = Point.valueOf(x1, y1, zt, Constants.unit); 301 Point p2 = Point.valueOf(x2, y2, zt, Constants.unit); 302 303 // Create tangent vectors at each end. 304 Vector t1 = derivative(x1, y1); 305 Vector t2 = derivative(x2, y2); 306 307 // Create the parabolic arc. 308 return CurveFactory.createParabolicArc(p1, t1, p2, t2); 309 } 310 311 /** 312 * Return the tangent vector to the general conic curve at the specified x,y location. 313 * 314 * @param x The abscissa for the point on the curve to return the tangent vector for. 315 * @param y The ordinate for the point on the curve to return the tangent vector for. 316 * @return The tangent vector for the conic curve at x,y. 317 */ 318 private Vector<Dimensionless> derivative(double x, double y) { 319 double num = 2 * Acoef * x + Bcoef * y + Dcoef; 320 double den = -2 * Ccoef * y - Bcoef * x - Ecoef; 321 322 Vector<Dimensionless> T; 323 if (abs(den) < Constants.Grain) { 324 // Infinite slope (vertical line). 325 T = Vector.valueOf(0, num, 0).toUnitVector(); 326 327 } else { 328 double dydx = num / den; 329 T = Vector.valueOf(1, dydx, 0).toUnitVector(); 330 } 331 332 return T; 333 } 334 335 /** 336 * Return a reference to the Transformable GeomElement contained in this IGES Entity. 337 * 338 * @return A reference to the Transformable GeomElement contained in this IGES Entity. 339 */ 340 @Override 341 protected Transformable getGeomElement() { 342 return curve; 343 } 344 345 /** 346 * Dump to String. 347 * 348 * @return String containing the resulting text. 349 */ 350 @Override 351 public String toString() { 352 StringBuilder outStr = new StringBuilder(super.toString()); 353 outStr.append("\n"); 354 355 outStr.append("A = "); outStr.append(Acoef); outStr.append("\n"); 356 outStr.append("B = "); outStr.append(Bcoef); outStr.append("\n"); 357 outStr.append("C = "); outStr.append(Ccoef); outStr.append("\n"); 358 outStr.append("D = "); outStr.append(Dcoef); outStr.append("\n"); 359 outStr.append("E = "); outStr.append(Ecoef); outStr.append("\n"); 360 outStr.append("F = "); outStr.append(Fcoef); outStr.append("\n"); 361 outStr.append("zt = "); outStr.append(zt); outStr.append("\n"); 362 outStr.append("x1 = "); outStr.append(x1); outStr.append("\n"); 363 outStr.append("y1 = "); outStr.append(y1); outStr.append("\n"); 364 outStr.append("x2 = "); outStr.append(x2); outStr.append("\n"); 365 outStr.append("y2 = "); outStr.append(y2); 366 367 return outStr.toString(); 368 } 369 370}