Merge pull request #38 from kruland2607/bug-print-fin-template
Fix bug with fin marking guide. If a rocket has some split fins
This commit is contained in:
commit
3eccae0fc7
@ -1,15 +1,5 @@
|
|||||||
package net.sf.openrocket.gui.print;
|
package net.sf.openrocket.gui.print;
|
||||||
|
|
||||||
import net.sf.openrocket.l10n.Translator;
|
|
||||||
import net.sf.openrocket.rocketcomponent.BodyTube;
|
|
||||||
import net.sf.openrocket.rocketcomponent.ExternalComponent;
|
|
||||||
import net.sf.openrocket.rocketcomponent.FinSet;
|
|
||||||
import net.sf.openrocket.rocketcomponent.LaunchLug;
|
|
||||||
import net.sf.openrocket.rocketcomponent.Rocket;
|
|
||||||
import net.sf.openrocket.rocketcomponent.RocketComponent;
|
|
||||||
import net.sf.openrocket.startup.Application;
|
|
||||||
|
|
||||||
import javax.swing.JPanel;
|
|
||||||
import java.awt.BasicStroke;
|
import java.awt.BasicStroke;
|
||||||
import java.awt.Color;
|
import java.awt.Color;
|
||||||
import java.awt.Graphics;
|
import java.awt.Graphics;
|
||||||
@ -21,12 +11,22 @@ import java.awt.geom.Path2D;
|
|||||||
import java.awt.image.BufferedImage;
|
import java.awt.image.BufferedImage;
|
||||||
import java.util.ArrayList;
|
import java.util.ArrayList;
|
||||||
import java.util.Collections;
|
import java.util.Collections;
|
||||||
import java.util.Comparator;
|
|
||||||
import java.util.Iterator;
|
import java.util.Iterator;
|
||||||
import java.util.LinkedHashMap;
|
import java.util.LinkedHashMap;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
import java.util.Map;
|
import java.util.Map;
|
||||||
|
|
||||||
|
import javax.swing.JPanel;
|
||||||
|
|
||||||
|
import net.sf.openrocket.l10n.Translator;
|
||||||
|
import net.sf.openrocket.rocketcomponent.BodyTube;
|
||||||
|
import net.sf.openrocket.rocketcomponent.ExternalComponent;
|
||||||
|
import net.sf.openrocket.rocketcomponent.FinSet;
|
||||||
|
import net.sf.openrocket.rocketcomponent.LaunchLug;
|
||||||
|
import net.sf.openrocket.rocketcomponent.Rocket;
|
||||||
|
import net.sf.openrocket.rocketcomponent.RocketComponent;
|
||||||
|
import net.sf.openrocket.startup.Application;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* This is the core Swing representation of a fin marking guide. It can handle multiple fin sets on the same or
|
* This is the core Swing representation of a fin marking guide. It can handle multiple fin sets on the same or
|
||||||
* different body tubes. One marking guide will be created for any body tube that has a finset. If a tube has multiple
|
* different body tubes. One marking guide will be created for any body tube that has a finset. If a tube has multiple
|
||||||
@ -63,6 +63,7 @@ public class FinMarkingGuide extends JPanel {
|
|||||||
* 2 PI radians (represents a circle).
|
* 2 PI radians (represents a circle).
|
||||||
*/
|
*/
|
||||||
public final static double TWO_PI = 2 * Math.PI;
|
public final static double TWO_PI = 2 * Math.PI;
|
||||||
|
public final static double PI = Math.PI;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* The I18N translator.
|
* The I18N translator.
|
||||||
@ -178,37 +179,37 @@ public class FinMarkingGuide extends JPanel {
|
|||||||
* |
|
* |
|
||||||
* | |
|
* | |
|
||||||
* P v
|
* P v
|
||||||
* a --- +----------------------------+ ------------
|
* a --- +----------------------------+ <- radialOrigin (in radians)
|
||||||
* g<------^-- x ------------>+ + ^
|
* g<------^-- x ------------>+ +
|
||||||
* e | + + |
|
* e | + +
|
||||||
* | + + baseYOffset
|
* | + +
|
||||||
* E | + + v
|
* E | + +
|
||||||
* d | +<----------Fin------------->+ -------------
|
* d | +<----------Fin------------->+ <- y+ (finRadialPosition - radialOrigin) / TWO_PI * circumferenceInPoints
|
||||||
* g | + +
|
* g | + +
|
||||||
* e | + +
|
* e | + +
|
||||||
* | | + +
|
* | | + +
|
||||||
* | | + +
|
* | | + +
|
||||||
* | | + + baseSpacing
|
|
||||||
* | | + +
|
* | | + +
|
||||||
* | | + +
|
* | | + +
|
||||||
* | | + +
|
* | | + +
|
||||||
* | | + +
|
* | | + +
|
||||||
* | | +<----------Fin------------->+ --------------
|
* | | + +
|
||||||
|
* | | +<----------Fin------------->+
|
||||||
* | | + +
|
* | | + +
|
||||||
* | circumferenceInPoints + +
|
* | circumferenceInPoints + +
|
||||||
* | | + +
|
* | | + +
|
||||||
* | | + +
|
* | | + +
|
||||||
* | | + + baseSpacing
|
* | | + +
|
||||||
* | | +<------Launch Lug --------->+ -----
|
* | | +<------Launch Lug --------->+
|
||||||
* | | + + \
|
* | | + +
|
||||||
* | | + + + yLLOffset
|
* | | + +
|
||||||
* | | + + /
|
* | | + +
|
||||||
* | | +<----------Fin------------->+ --------------
|
* | | +<----------Fin------------->+
|
||||||
* | | + + ^
|
* | | + +
|
||||||
* | | + + |
|
* | | + +
|
||||||
* | | + + baseYOffset
|
* | | + +
|
||||||
* | v + + v
|
* | v + +
|
||||||
* | --- +----------------------------+ --------------
|
* | --- +----------------------------+ <- radialOrigin + TWO_PI
|
||||||
*
|
*
|
||||||
* |<-------- width ----------->|
|
* |<-------- width ----------->|
|
||||||
*
|
*
|
||||||
@ -250,53 +251,33 @@ public class FinMarkingGuide extends JPanel {
|
|||||||
|
|
||||||
drawMarkingGuide(g2, x, y, (int) Math.ceil(circumferenceInPoints), width);
|
drawMarkingGuide(g2, x, y, (int) Math.ceil(circumferenceInPoints), width);
|
||||||
|
|
||||||
//Sort so that fins always precede lugs
|
double radialOrigin = findRadialOrigin(componentList);
|
||||||
sort(componentList);
|
|
||||||
|
|
||||||
boolean hasMultipleComponents = componentList.size() > 1;
|
boolean hasMultipleComponents = componentList.size() > 1;
|
||||||
|
|
||||||
double baseSpacing = 0d;
|
|
||||||
double baseYOrigin = 0;
|
|
||||||
double finRadial = 0d;
|
|
||||||
int yFirstFin = y;
|
|
||||||
int yLastFin = y;
|
|
||||||
boolean firstFinSet = true;
|
|
||||||
|
|
||||||
//fin1: 42 fin2: 25
|
//fin1: 42 fin2: 25
|
||||||
for (ExternalComponent externalComponent : componentList) {
|
for (ExternalComponent externalComponent : componentList) {
|
||||||
if (externalComponent instanceof FinSet) {
|
if (externalComponent instanceof FinSet) {
|
||||||
FinSet fins = (FinSet) externalComponent;
|
FinSet fins = (FinSet) externalComponent;
|
||||||
int finCount = fins.getFinCount();
|
int finCount = fins.getFinCount();
|
||||||
int offset = 0;
|
double baseAngularSpacing = (TWO_PI / finCount);
|
||||||
baseSpacing = (circumferenceInPoints / finCount);
|
double baseAngularOffset = fins.getBaseRotation();
|
||||||
double baseRotation = fins.getBaseRotation();
|
|
||||||
if (!firstFinSet) {
|
|
||||||
//Adjust the rotation to a positive number.
|
|
||||||
while (baseRotation < 0) {
|
|
||||||
baseRotation += TWO_PI / finCount;
|
|
||||||
}
|
|
||||||
offset = computeYOffset(y, circumferenceInPoints, baseSpacing, baseYOrigin, finRadial, baseRotation);
|
|
||||||
}
|
|
||||||
else {
|
|
||||||
//baseYOrigin is the distance from the top of the marking guide to the first fin of the first fin set.
|
|
||||||
//This measurement is used to base all subsequent finsets and lugs off of.
|
|
||||||
baseYOrigin = baseSpacing / 2;
|
|
||||||
offset = (int) (baseYOrigin) + y;
|
|
||||||
firstFinSet = false;
|
|
||||||
}
|
|
||||||
yFirstFin = y;
|
|
||||||
yLastFin = y;
|
|
||||||
finRadial = baseRotation;
|
|
||||||
|
|
||||||
//Draw the fin marking lines.
|
//Draw the fin marking lines.
|
||||||
for (int fin = 0; fin < finCount; fin++) {
|
for (int fin = 0; fin < finCount; fin++) {
|
||||||
if (fin > 0) {
|
double angle = baseAngularOffset + fin * baseAngularSpacing - radialOrigin;
|
||||||
offset += baseSpacing;
|
// Translate angle into pixels using a linear transformation:
|
||||||
yLastFin = offset;
|
// radialOrigin -> y
|
||||||
|
// radialOrigin + TWO_PI -> y + circumferenceInPoints
|
||||||
|
|
||||||
|
while (angle < 0) {
|
||||||
|
angle += TWO_PI;
|
||||||
}
|
}
|
||||||
else {
|
while (angle > TWO_PI) {
|
||||||
yFirstFin = offset;
|
angle -= TWO_PI;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
int offset = (int) Math.round(y + angle / TWO_PI * circumferenceInPoints);
|
||||||
|
|
||||||
drawDoubleArrowLine(g2, x, offset, x + width, offset);
|
drawDoubleArrowLine(g2, x, offset, x + width, offset);
|
||||||
// if (hasMultipleComponents) {
|
// if (hasMultipleComponents) {
|
||||||
g2.drawString(externalComponent.getName(), x + (width / 3), offset - 2);
|
g2.drawString(externalComponent.getName(), x + (width / 3), offset - 2);
|
||||||
@ -305,16 +286,11 @@ public class FinMarkingGuide extends JPanel {
|
|||||||
}
|
}
|
||||||
else if (externalComponent instanceof LaunchLug) {
|
else if (externalComponent instanceof LaunchLug) {
|
||||||
LaunchLug lug = (LaunchLug) externalComponent;
|
LaunchLug lug = (LaunchLug) externalComponent;
|
||||||
double yLLOffset = (lug.getRadialDirection() - finRadial) / TWO_PI;
|
double angle = lug.getRadialDirection() - radialOrigin;
|
||||||
//The placement of the lug line must respect the boundary of the outer marking guide. In order
|
while (angle < 0) {
|
||||||
//to do that, place it above or below either the top or bottom fin line, based on the difference
|
angle += TWO_PI;
|
||||||
//between their rotational directions.
|
|
||||||
if (yLLOffset < 0) {
|
|
||||||
yLLOffset = yLLOffset * circumferenceInPoints + yLastFin;
|
|
||||||
}
|
|
||||||
else {
|
|
||||||
yLLOffset = yLLOffset * circumferenceInPoints + yFirstFin;
|
|
||||||
}
|
}
|
||||||
|
int yLLOffset = (int) Math.round(y + angle / TWO_PI * circumferenceInPoints);
|
||||||
drawDoubleArrowLine(g2, x, (int) yLLOffset, x + width, (int) yLLOffset);
|
drawDoubleArrowLine(g2, x, (int) yLLOffset, x + width, (int) yLLOffset);
|
||||||
g2.drawString(lug.getName(), x + (width / 3), (int) yLLOffset - 2);
|
g2.drawString(lug.getName(), x + (width / 3), (int) yLLOffset - 2);
|
||||||
|
|
||||||
@ -322,7 +298,7 @@ public class FinMarkingGuide extends JPanel {
|
|||||||
}
|
}
|
||||||
//Only if the tube has a lug or multiple finsets does the orientation of the marking guide matter. So print 'Front'.
|
//Only if the tube has a lug or multiple finsets does the orientation of the marking guide matter. So print 'Front'.
|
||||||
if (hasMultipleComponents) {
|
if (hasMultipleComponents) {
|
||||||
drawFrontIndication(g2, x, y, (int) baseSpacing, (int) circumferenceInPoints, width);
|
drawFrontIndication(g2, x, y, 0, (int) circumferenceInPoints, width);
|
||||||
}
|
}
|
||||||
|
|
||||||
//At most, two marking guides horizontally. After that, move down and back to the left margin.
|
//At most, two marking guides horizontally. After that, move down and back to the left margin.
|
||||||
@ -339,31 +315,73 @@ public class FinMarkingGuide extends JPanel {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Compute the y offset for the next fin line.
|
* This function finds a origin in radians for the template so no component is on the template seam.
|
||||||
*
|
*
|
||||||
* @param y the top margin
|
* If no fin or launch lug is at 0.0 radians, then the origin is 0. If there is one, then half the distance
|
||||||
* @param circumferenceInPoints the circumference (height) of the guide
|
* between the two are taken.
|
||||||
* @param baseSpacing the circumference / fin count
|
|
||||||
* @param baseYOrigin the offset from the top of the guide to the first fin of the first fin set drawn
|
|
||||||
* @param prevBaseRotation the rotation of the previous finset
|
|
||||||
* @param baseRotation the rotation of the current finset
|
|
||||||
*
|
*
|
||||||
* @return number of points from the top of the marking guide to the line to be drawn
|
* @param components
|
||||||
|
* @return
|
||||||
*/
|
*/
|
||||||
private int computeYOffset(int y, double circumferenceInPoints, double baseSpacing, double baseYOrigin, double prevBaseRotation, double baseRotation) {
|
private double findRadialOrigin(List<ExternalComponent> components) {
|
||||||
int offset;
|
|
||||||
double finRadialDifference = (baseRotation - prevBaseRotation) / TWO_PI;
|
ArrayList<Double> positions = new ArrayList<Double>(3 * components.size());
|
||||||
//If the fin line would be off the top of the marking guide, then readjust.
|
|
||||||
if (baseYOrigin + finRadialDifference * circumferenceInPoints < 0) {
|
for (ExternalComponent component : components) {
|
||||||
offset = (int) (baseYOrigin + baseSpacing + finRadialDifference * circumferenceInPoints) + y;
|
|
||||||
|
if (component instanceof LaunchLug) {
|
||||||
|
double componentPosition = ((LaunchLug) component).getRadialDirection();
|
||||||
|
|
||||||
|
positions.add(makeZeroTwoPi(componentPosition));
|
||||||
}
|
}
|
||||||
else if (baseYOrigin - finRadialDifference * circumferenceInPoints > 0) {
|
|
||||||
offset = (int) (finRadialDifference * circumferenceInPoints + baseYOrigin) + y;
|
if (component instanceof FinSet) {
|
||||||
|
FinSet fins = (FinSet) component;
|
||||||
|
double basePosition = fins.getBaseRotation();
|
||||||
|
double angle = TWO_PI / fins.getFinCount();
|
||||||
|
for (int i = fins.getFinCount(); i > 0; i--) {
|
||||||
|
positions.add(makeZeroTwoPi(basePosition));
|
||||||
|
basePosition += angle;
|
||||||
}
|
}
|
||||||
else {
|
|
||||||
offset = (int) (finRadialDifference * circumferenceInPoints - baseYOrigin) + y;
|
|
||||||
}
|
}
|
||||||
return offset;
|
}
|
||||||
|
|
||||||
|
Collections.sort(positions);
|
||||||
|
|
||||||
|
Double[] pos = positions.toArray(new Double[0]);
|
||||||
|
|
||||||
|
if (pos.length == 1) {
|
||||||
|
|
||||||
|
return makeZeroTwoPi(pos[0] + PI);
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
double biggestDistance = TWO_PI - pos[pos.length - 1] + pos[0];
|
||||||
|
double center = makeZeroTwoPi(pos[0] - biggestDistance / 2.0);
|
||||||
|
|
||||||
|
for (int i = 1; i < pos.length; i++) {
|
||||||
|
|
||||||
|
double d = pos[i] - pos[i - 1];
|
||||||
|
if (d > biggestDistance) {
|
||||||
|
biggestDistance = d;
|
||||||
|
center = makeZeroTwoPi(pos[i - 1] + biggestDistance / 2.0);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return center;
|
||||||
|
}
|
||||||
|
|
||||||
|
private static double makeZeroTwoPi(double value) {
|
||||||
|
|
||||||
|
double v = value;
|
||||||
|
while (v < 0) {
|
||||||
|
v += TWO_PI;
|
||||||
|
}
|
||||||
|
while (v > TWO_PI) {
|
||||||
|
v -= TWO_PI;
|
||||||
|
}
|
||||||
|
|
||||||
|
return v;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -382,26 +400,6 @@ public class FinMarkingGuide extends JPanel {
|
|||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
|
||||||
* Sort a list of ExternalComponent in-place. Forces FinSets to precede Launch Lugs.
|
|
||||||
*
|
|
||||||
* @param componentList a list of ExternalComponent
|
|
||||||
*/
|
|
||||||
private void sort(List<ExternalComponent> componentList) {
|
|
||||||
Collections.sort(componentList, new Comparator<ExternalComponent>() {
|
|
||||||
@Override
|
|
||||||
public int compare(ExternalComponent o1, ExternalComponent o2) {
|
|
||||||
if (o1 instanceof FinSet) {
|
|
||||||
return -1;
|
|
||||||
}
|
|
||||||
if (o2 instanceof FinSet) {
|
|
||||||
return 1;
|
|
||||||
}
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Draw the marking guide outline.
|
* Draw the marking guide outline.
|
||||||
*
|
*
|
||||||
@ -474,10 +472,10 @@ public class FinMarkingGuide extends JPanel {
|
|||||||
int len = x2 - x1;
|
int len = x2 - x1;
|
||||||
|
|
||||||
g2.drawLine(x1, y1, x1 + len, y2);
|
g2.drawLine(x1, y1, x1 + len, y2);
|
||||||
g2.fillPolygon(new int[]{x1 + len, x1 + len - ARROW_SIZE, x1 + len - ARROW_SIZE, x1 + len},
|
g2.fillPolygon(new int[] { x1 + len, x1 + len - ARROW_SIZE, x1 + len - ARROW_SIZE, x1 + len },
|
||||||
new int[]{y2, y2 - ARROW_SIZE / 2, y2 + ARROW_SIZE / 2, y2}, 4);
|
new int[] { y2, y2 - ARROW_SIZE / 2, y2 + ARROW_SIZE / 2, y2 }, 4);
|
||||||
|
|
||||||
g2.fillPolygon(new int[]{x1, x1 + ARROW_SIZE, x1 + ARROW_SIZE, x1},
|
g2.fillPolygon(new int[] { x1, x1 + ARROW_SIZE, x1 + ARROW_SIZE, x1 },
|
||||||
new int[]{y1, y1 - ARROW_SIZE / 2, y1 + ARROW_SIZE / 2, y1}, 4);
|
new int[] { y1, y1 - ARROW_SIZE / 2, y1 + ARROW_SIZE / 2, y1 }, 4);
|
||||||
}
|
}
|
||||||
}
|
}
|
Loading…
x
Reference in New Issue
Block a user