Print support for clustered centering rings.
This commit is contained in:
parent
eb0cfe141e
commit
dbd72738c5
@ -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) {
|
||||
|
@ -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.
|
||||
*/
|
||||
|
Loading…
x
Reference in New Issue
Block a user