Print support for clustered centering rings.

This commit is contained in:
Doug Pedrick 2012-05-30 22:41:01 +00:00
parent eb0cfe141e
commit dbd72738c5
2 changed files with 159 additions and 20 deletions

View File

@ -1,16 +1,24 @@
package net.sf.openrocket.gui.print;
import net.sf.openrocket.gui.print.visitor.CenteringRingStrategy;
import net.sf.openrocket.rocketcomponent.CenteringRing;
import net.sf.openrocket.rocketcomponent.ClusterConfiguration;
import net.sf.openrocket.rocketcomponent.InnerTube;
import net.sf.openrocket.util.ArrayList;
import net.sf.openrocket.util.Coordinate;
import java.awt.Color;
import java.awt.Graphics;
import java.awt.Graphics2D;
import java.awt.Shape;
import java.awt.geom.Ellipse2D;
import java.util.HashSet;
import java.util.List;
import java.util.Set;
/**
* This class creates a renderable centering ring. It depends only on AWT/Swing and can be called from other
* actors (like iText handlers) to render the centering ring on different graphics contexts.
* This class creates a renderable centering ring. It depends only on AWT/Swing and can be called from other actors
* (like iText handlers) to render the centering ring on different graphics contexts.
*/
public class PrintableCenteringRing extends AbstractPrintable<CenteringRing> {
/**
@ -24,12 +32,79 @@ public class PrintableCenteringRing extends AbstractPrintable<CenteringRing> {
private final int lineLength = 10;
/**
* Construct a printable nose cone.
*
* @param theRing the component to print
* A set of the inner 'holes'. At least one, but will have many if clustered.
*/
public PrintableCenteringRing(CenteringRing theRing) {
private Set<CenteringRingStrategy.Dimension> innerCenterPoints = new HashSet<CenteringRingStrategy.Dimension>();
/**
* Construct a simple, non-clustered, printable centering ring.
*
* @param theRing the component to print
* @param theMotorMount the motor mount if clustered, else null
*/
private PrintableCenteringRing(CenteringRing theRing, InnerTube theMotorMount) {
super(false, theRing);
if (theMotorMount == null || theMotorMount.getClusterConfiguration().equals(ClusterConfiguration.SINGLE)) {
//Single motor.
innerCenterPoints.add(new CenteringRingStrategy.Dimension((float) PrintUnit.METERS.toPoints(target.getOuterRadius()),
(float) PrintUnit.METERS.toPoints(target.getOuterRadius())));
}
else {
List<Coordinate> coords = theMotorMount.getClusterPoints();
populateCenterPoints(coords);
}
}
/**
* Constructor for a clustered centering ring.
*
* @param theRing the centering ring component
* @param theMotorMounts a list of the motor mount tubes that are physically supported by the centering ring
*/
private PrintableCenteringRing(CenteringRing theRing, List<InnerTube> theMotorMounts) {
super(false, theRing);
List<Coordinate> points = new ArrayList<Coordinate>();
//Transform the radial positions of the tubes.
for (InnerTube it : theMotorMounts) {
double y = it.getRadialShiftY();
double z = it.getRadialShiftZ();
Coordinate coordinate = new Coordinate(0, y, z);
points.add(coordinate);
}
populateCenterPoints(points);
}
/**
* Factory method to create a printable centering ring.
*
* @param theRing the component to print
* @param theMotorMounts the motor mount if clustered, else null
*/
public static PrintableCenteringRing create(CenteringRing theRing, List<InnerTube> theMotorMounts) {
if (theMotorMounts == null) {
return new PrintableCenteringRing(theRing, (InnerTube) null);
}
else if (theMotorMounts.size() <= 1) {
return new PrintableCenteringRing(theRing, theMotorMounts.isEmpty() ? null : theMotorMounts.get(0));
}
else {
return new PrintableCenteringRing(theRing, theMotorMounts);
}
}
/**
* Initialize the set of center points for each motor mount tube, based on the tube coordinates.
*
* @param theCoords the list of tube coordinates; each coordinate is in the OR units (meters) and must be
* transformed to the printing (points) coordinate system
*/
private void populateCenterPoints(final List<Coordinate> theCoords) {
float radius = (float) PrintUnit.METERS.toPoints(target.getOuterRadius());
for (Coordinate coordinate : theCoords) {
innerCenterPoints.add(new CenteringRingStrategy.Dimension((float) PrintUnit.METERS.toPoints
(coordinate.y) + radius,
(float) PrintUnit.METERS.toPoints(coordinate.z) + radius));
}
}
/**
@ -55,33 +130,43 @@ public class PrintableCenteringRing extends AbstractPrintable<CenteringRing> {
double radius = PrintUnit.METERS.toPoints(target.getOuterRadius());
Color original = g2.getBackground();
double x = 0;
double y = 0;
Shape outerCircle = new Ellipse2D.Double(x, y, radius * 2, radius * 2);
Shape outerCircle = new Ellipse2D.Double(0, 0, radius * 2, radius * 2);
g2.setColor(Color.lightGray);
g2.fill(outerCircle);
g2.setColor(Color.black);
g2.draw(outerCircle);
x += radius;
y += radius;
double innerRadius = PrintUnit.METERS.toPoints(target.getInnerRadius());
Shape innerCircle = new Ellipse2D.Double(x - innerRadius, y - innerRadius, innerRadius * 2, innerRadius * 2);
for (CenteringRingStrategy.Dimension next : innerCenterPoints) {
drawInnerCircle(g2, next.getWidth(), next.getHeight());
}
g2.setColor(original);
}
/**
* Draw one inner circle, representing the motor mount tube, with cross hairs in the center.
*
* @param g2 the graphics context
* @param theCenterX the center x in points
* @param theCenterY the center y in points
*/
private void drawInnerCircle(final Graphics2D g2, final double theCenterX, final double theCenterY) {
double innerRadius = PrintUnit.METERS.toPoints(target.getInnerRadius());
Shape innerCircle = new Ellipse2D.Double(theCenterX - innerRadius, theCenterY - innerRadius, innerRadius * 2, innerRadius * 2);
g2.setColor(Color.white);
g2.fill(innerCircle);
g2.setColor(Color.black);
g2.draw(innerCircle);
drawCross(g2, (int) x, (int) y, lineLength, lineLength);
drawCross(g2, (int) theCenterX, (int) theCenterY, lineLength, lineLength);
}
/**
* Draw the center cross-hair.
*
* @param g the graphics context
* @param x the x coordinate of the center point
* @param y the y coordinate of the center point
* @param width the width in pixels of the horizontal hair
* @param g the graphics context
* @param x the x coordinate of the center point
* @param y the y coordinate of the center point
* @param width the width in pixels of the horizontal hair
* @param height the width in pixels of the vertical hair
*/
private void drawCross(Graphics g, int x, int y, int width, int height) {

View File

@ -10,8 +10,10 @@ import net.sf.openrocket.gui.print.PrintUnit;
import net.sf.openrocket.gui.print.PrintableCenteringRing;
import net.sf.openrocket.logging.LogHelper;
import net.sf.openrocket.rocketcomponent.CenteringRing;
import net.sf.openrocket.rocketcomponent.InnerTube;
import net.sf.openrocket.rocketcomponent.RocketComponent;
import net.sf.openrocket.startup.Application;
import net.sf.openrocket.util.ArrayList;
import java.awt.image.BufferedImage;
import java.util.List;
@ -88,6 +90,58 @@ public class CenteringRingStrategy {
}
}
/**
* Find the inner tubes that are physically supported by the given centering ring. Note that this only looks for
* motor mount tubes that are siblings to the centering ring.
*
* @param rc the centering ring, for which all motor mount tubes that run through it are located.
*
* @return the list of tubes found
*/
private List<InnerTube> findMotorMount(CenteringRing rc) {
RocketComponent parent = rc.getParent();
List<RocketComponent> siblings = parent.getChildren();
List<InnerTube> mounts = new ArrayList<InnerTube>();
for (RocketComponent rocketComponents : siblings) {
if (rocketComponents != rc) {
if (rocketComponents instanceof InnerTube) {
InnerTube it = (InnerTube) rocketComponents;
if (it.isMotorMount()) {
if (overlaps(rc, it)) {
mounts.add(it);
}
}
}
}
}
return mounts;
}
/**
* Determine if the centering ring physically overlaps with the inner tube.
*
* @param one the centering ring
* @param two the inner body tube
*
* @return true if the two physically intersect, from which we infer that the centering ring supports the tube
*/
private boolean overlaps(CenteringRing one, InnerTube two) {
final double crTopPosition = one.asPositionValue(RocketComponent.Position.ABSOLUTE, one.getParent());
final double mmTopPosition = two.asPositionValue(RocketComponent.Position.ABSOLUTE, two.getParent());
final double crBottomPosition = one.getLength() + crTopPosition;
final double mmBottomPosition = two.getLength() + mmTopPosition;
if (crTopPosition >= mmTopPosition && crTopPosition <= mmBottomPosition) {
return true;
}
if (crBottomPosition >= mmTopPosition && crBottomPosition <= mmBottomPosition) {
return true;
}
return false;
}
/**
* The core behavior of this visitor.
*
@ -97,7 +151,7 @@ public class CenteringRingStrategy {
private void render(final CenteringRing component) {
try {
AbstractPrintable pfs;
pfs = new PrintableCenteringRing(component);
pfs = PrintableCenteringRing.create(component, findMotorMount(component));
java.awt.Dimension size = pfs.getSize();
final Dimension pageSize = getPageSize();
@ -150,7 +204,7 @@ public class CenteringRingStrategy {
/**
* Convenience class to model a dimension.
*/
class Dimension {
public static class Dimension {
/**
* Width, in points.
*/