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;
|
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.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.Color;
|
||||||
import java.awt.Graphics;
|
import java.awt.Graphics;
|
||||||
import java.awt.Graphics2D;
|
import java.awt.Graphics2D;
|
||||||
import java.awt.Shape;
|
import java.awt.Shape;
|
||||||
import java.awt.geom.Ellipse2D;
|
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
|
* This class creates a renderable centering ring. It depends only on AWT/Swing and can be called from other actors
|
||||||
* actors (like iText handlers) to render the centering ring on different graphics contexts.
|
* (like iText handlers) to render the centering ring on different graphics contexts.
|
||||||
*/
|
*/
|
||||||
public class PrintableCenteringRing extends AbstractPrintable<CenteringRing> {
|
public class PrintableCenteringRing extends AbstractPrintable<CenteringRing> {
|
||||||
/**
|
/**
|
||||||
@ -24,12 +32,79 @@ public class PrintableCenteringRing extends AbstractPrintable<CenteringRing> {
|
|||||||
private final int lineLength = 10;
|
private final int lineLength = 10;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Construct a printable nose cone.
|
* A set of the inner 'holes'. At least one, but will have many if clustered.
|
||||||
*
|
|
||||||
* @param theRing the component to print
|
|
||||||
*/
|
*/
|
||||||
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);
|
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());
|
double radius = PrintUnit.METERS.toPoints(target.getOuterRadius());
|
||||||
|
|
||||||
Color original = g2.getBackground();
|
Color original = g2.getBackground();
|
||||||
double x = 0;
|
Shape outerCircle = new Ellipse2D.Double(0, 0, radius * 2, radius * 2);
|
||||||
double y = 0;
|
|
||||||
Shape outerCircle = new Ellipse2D.Double(x, y, radius * 2, radius * 2);
|
|
||||||
g2.setColor(Color.lightGray);
|
g2.setColor(Color.lightGray);
|
||||||
g2.fill(outerCircle);
|
g2.fill(outerCircle);
|
||||||
g2.setColor(Color.black);
|
g2.setColor(Color.black);
|
||||||
g2.draw(outerCircle);
|
g2.draw(outerCircle);
|
||||||
x += radius;
|
|
||||||
y += radius;
|
|
||||||
|
|
||||||
double innerRadius = PrintUnit.METERS.toPoints(target.getInnerRadius());
|
for (CenteringRingStrategy.Dimension next : innerCenterPoints) {
|
||||||
Shape innerCircle = new Ellipse2D.Double(x - innerRadius, y - innerRadius, innerRadius * 2, innerRadius * 2);
|
drawInnerCircle(g2, next.getWidth(), next.getHeight());
|
||||||
|
}
|
||||||
g2.setColor(original);
|
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.fill(innerCircle);
|
||||||
g2.setColor(Color.black);
|
g2.setColor(Color.black);
|
||||||
g2.draw(innerCircle);
|
g2.draw(innerCircle);
|
||||||
|
|
||||||
drawCross(g2, (int) x, (int) y, lineLength, lineLength);
|
drawCross(g2, (int) theCenterX, (int) theCenterY, lineLength, lineLength);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Draw the center cross-hair.
|
* Draw the center cross-hair.
|
||||||
*
|
*
|
||||||
* @param g the graphics context
|
* @param g the graphics context
|
||||||
* @param x the x coordinate of the center point
|
* @param x the x coordinate of the center point
|
||||||
* @param y the y 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 width the width in pixels of the horizontal hair
|
||||||
* @param height the width in pixels of the vertical hair
|
* @param height the width in pixels of the vertical hair
|
||||||
*/
|
*/
|
||||||
private void drawCross(Graphics g, int x, int y, int width, int height) {
|
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.gui.print.PrintableCenteringRing;
|
||||||
import net.sf.openrocket.logging.LogHelper;
|
import net.sf.openrocket.logging.LogHelper;
|
||||||
import net.sf.openrocket.rocketcomponent.CenteringRing;
|
import net.sf.openrocket.rocketcomponent.CenteringRing;
|
||||||
|
import net.sf.openrocket.rocketcomponent.InnerTube;
|
||||||
import net.sf.openrocket.rocketcomponent.RocketComponent;
|
import net.sf.openrocket.rocketcomponent.RocketComponent;
|
||||||
import net.sf.openrocket.startup.Application;
|
import net.sf.openrocket.startup.Application;
|
||||||
|
import net.sf.openrocket.util.ArrayList;
|
||||||
|
|
||||||
import java.awt.image.BufferedImage;
|
import java.awt.image.BufferedImage;
|
||||||
import java.util.List;
|
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.
|
* The core behavior of this visitor.
|
||||||
*
|
*
|
||||||
@ -97,7 +151,7 @@ public class CenteringRingStrategy {
|
|||||||
private void render(final CenteringRing component) {
|
private void render(final CenteringRing component) {
|
||||||
try {
|
try {
|
||||||
AbstractPrintable pfs;
|
AbstractPrintable pfs;
|
||||||
pfs = new PrintableCenteringRing(component);
|
pfs = PrintableCenteringRing.create(component, findMotorMount(component));
|
||||||
|
|
||||||
java.awt.Dimension size = pfs.getSize();
|
java.awt.Dimension size = pfs.getSize();
|
||||||
final Dimension pageSize = getPageSize();
|
final Dimension pageSize = getPageSize();
|
||||||
@ -150,7 +204,7 @@ public class CenteringRingStrategy {
|
|||||||
/**
|
/**
|
||||||
* Convenience class to model a dimension.
|
* Convenience class to model a dimension.
|
||||||
*/
|
*/
|
||||||
class Dimension {
|
public static class Dimension {
|
||||||
/**
|
/**
|
||||||
* Width, in points.
|
* Width, in points.
|
||||||
*/
|
*/
|
||||||
|
Loading…
x
Reference in New Issue
Block a user