From d347191a2f4c186ccf5c9e659e101402c29ed986 Mon Sep 17 00:00:00 2001 From: Bill Kuker Date: Tue, 14 Apr 2009 21:01:31 +0000 Subject: [PATCH] Firest checkin of rotated grain --- .../motorsim/grain/RotatedShapeGrain.java | 208 ++++++++++++++++++ 1 file changed, 208 insertions(+) create mode 100644 src/com/billkuker/rocketry/motorsim/grain/RotatedShapeGrain.java diff --git a/src/com/billkuker/rocketry/motorsim/grain/RotatedShapeGrain.java b/src/com/billkuker/rocketry/motorsim/grain/RotatedShapeGrain.java new file mode 100644 index 0000000..0c70fe0 --- /dev/null +++ b/src/com/billkuker/rocketry/motorsim/grain/RotatedShapeGrain.java @@ -0,0 +1,208 @@ +package com.billkuker.rocketry.motorsim.grain; + +import java.awt.Shape; +import java.awt.geom.AffineTransform; +import java.awt.geom.Area; +import java.awt.geom.Ellipse2D; +import java.awt.geom.GeneralPath; +import java.awt.geom.PathIterator; +import java.awt.geom.Rectangle2D; + +import javax.measure.quantity.Length; +import javax.measure.quantity.Volume; +import javax.measure.unit.SI; + +import org.jscience.physics.amount.Amount; + +import com.billkuker.rocketry.motorsim.Grain; +import com.billkuker.rocketry.motorsim.visual.Editor; +import com.billkuker.rocketry.motorsim.visual.GrainPanel; + +public class RotatedShapeGrain implements Grain { + + BurningShape shape = new BurningShape(); + + Amount web = null; + + { + Shape outside = new Rectangle2D.Double(0,0,15,70); + shape.add( outside ); + shape.inhibit( outside ); + shape.subtract( new Rectangle2D.Double(0,50,5,70)); + shape.subtract(new Rectangle2D.Double(0, 70, 15, 10)); + } + + @Override + public Area getCrossSection(Amount regression) { + Area ret = new Area(); + for( Area a : ShapeUtil.separate(shape.getShape(regression))){ + Rectangle2D b = a.getBounds2D(); + Ellipse2D inner = new Ellipse2D.Double(-b.getMinX(), -b.getMinX(), b.getMinX()*2, b.getMinX()*2); + Ellipse2D outer = new Ellipse2D.Double(-b.getMaxX(), -b.getMaxX(), b.getMaxX()*2, b.getMaxX()*2); + Area aa = new Area(outer); + aa.subtract(new Area(inner)); + ret.add(aa); + } + return ret; + } + + @Override + public Area getSideView(Amount regression) { + Area a = new Area(); + Area reg = shape.getShape(regression); + a.add(reg); + a.transform(AffineTransform.getScaleInstance(-1, 1)); + a.add(reg); + return a; + } + + @Override + public Amount surfaceArea( + Amount regression) { + Amount zero = Amount.valueOf(0, javax.measure.quantity.Area.UNIT); + + if (regression.isGreaterThan(webThickness())) + return zero; + + java.awt.geom.Area burn = shape.getShape(regression); + + if (burn.isEmpty()) + return zero; + + burn.subtract(shape.getShape(regression.plus(Amount.valueOf(.001, + SI.MILLIMETER)))); + + System.out.println(regression); + + double sqmm = yRotatedSurfaceArea(burn); + + + return Amount.valueOf(sqmm, SI.MILLIMETER.pow(2).asType(javax.measure.quantity.Area.class)).divide(2); + + } + + @Override + public Amount volume(Amount regression) { + Area squared = new Area(square(shape.getShape(regression))); + Amount sum = Amount.valueOf(0, SI.SQUARE_METRE); + for( Area a: ShapeUtil.separate(squared) ){ + sum = sum.plus( ShapeUtil.area(a) ); + } + Amount v = sum.times(Amount.valueOf(Math.PI, SI.MILLIMETER)).to(Volume.UNIT); + return v; + } + + @Override + public Amount webThickness() { + if ( web != null ) + return web; + Rectangle2D b = shape.getShape(Amount.valueOf(0, SI.MILLIMETER)).getBounds2D(); + double webmm = b.getWidth()>b.getHeight()?b.getWidth():b.getHeight(); + return web = Amount.valueOf(webmm, SI.MILLIMETER); + } + + + public static void main(String args[]) throws Exception { + RotatedShapeGrain e = new RotatedShapeGrain(); + new Editor(e).show(); + new GrainPanel(e).show(); + } + + private Shape square(java.awt.geom.Area a) { + PathIterator i = a.getPathIterator(new AffineTransform(), 0.001); + GeneralPath cur = new GeneralPath(); + + double last[] = {0,0}; + while (!i.isDone()) { + double coords[] = new double[6]; + int type = i.currentSegment(coords); + switch (type) { + case PathIterator.SEG_CLOSE: + cur.closePath(); + break; + case PathIterator.SEG_MOVETO: + cur.moveTo(Math.pow(coords[0],2), coords[1]); + last[0] = coords[0]; + last[1] = coords[1]; + break; + case PathIterator.SEG_CUBICTO: + throw new Error("Non-flattened geometry!"); + case PathIterator.SEG_LINETO: + double x = last[0]; + double y = last[1]; + double len = Math.sqrt(Math.pow(last[0]-coords[0], 2) + Math.pow(last[1]-coords[1], 2)); + int steps = (int)(len / .01) + 5; + for (int s = 0; s < steps; s++) { + x += (coords[0] - last[0]) / steps; + y += (coords[1] - last[1]) / steps; + cur.lineTo(Math.pow(x, 2), y); + } + last[0] = coords[0]; + last[1] = coords[1]; + break; + case PathIterator.SEG_QUADTO: + throw new Error("Non-flattened geometry!"); + + } + i.next(); + } + return cur; + } + + private double yRotatedSurfaceArea(java.awt.geom.Area a) { + PathIterator i = a.getPathIterator(new AffineTransform(), .001); + double x = 0, y = 0; + double mx = 0, my = 0; + double len = 0; + while (!i.isDone()) { + double coords[] = new double[6]; + int type = i.currentSegment(coords); + if (type == PathIterator.SEG_LINETO || type == PathIterator.SEG_CLOSE) { + + + double nx = coords[0]; + double ny = coords[1]; + + if ( type == PathIterator.SEG_CLOSE ){ + nx = mx; + ny = my; + } + + double dy = Math.abs(y-ny); + double dx = Math.abs(x-nx); + double xl = x>nx?x:nx; + double xs = x