1 package net.sf.openrocket.gui.util;
3 import java.awt.image.BufferedImage;
5 import java.io.IOException;
7 import java.util.ListIterator;
9 import javax.imageio.ImageIO;
11 import net.sf.openrocket.l10n.LocalizedIOException;
12 import net.sf.openrocket.util.ArrayList;
13 import net.sf.openrocket.util.Coordinate;
15 public class CustomFinImporter {
17 private enum FacingDirections {
22 private FacingDirections facing;
23 private int currentX, currentY;
27 public List<Coordinate> getPoints(File file) throws IOException {
28 ArrayList<Coordinate> points = new ArrayList<Coordinate>();
30 BufferedImage pic = ImageIO.read(file);
32 // Set initial values for parsing
34 facing = FacingDirections.UP;
36 if (validateImage(pic)) {
37 points.add(Coordinate.NUL);
40 throw new LocalizedIOException("CustomFinImport.error.badimage");
43 optimizePoints(points);
48 private boolean validateImage(BufferedImage pic) {
49 int height = pic.getHeight();
50 int width = pic.getWidth();
51 Boolean bottomEdgeFound = false;
53 for (int x = 0; x < width; ++x) {
54 for (int y = 0; y < height; ++y) {
55 int pixel = pic.getRGB(x, y) & 0x00FFFFFF; // Clear alpha, we don't care about it
56 if ((pixel == 0xFFFFFF) || (pixel == 0)) // black or white only
58 if ((x == 0) || (x == width - 1) || (y == 0)) {
59 // Left, right and top must have no black (fin)
62 } else if (y == height - 1) {
64 bottomEdgeFound = true;
70 // Found something other than a black or white pixel
75 return bottomEdgeFound;
78 private void loadFin(BufferedImage pic, ArrayList<Coordinate> points) {
79 boolean calledTurnedAround = false;
80 int height = pic.getHeight();
83 currentY = pic.getHeight() - 1;
86 if (CheckLeftIsFin(pic, currentX, currentY))
88 else if (CheckForwardIsFin(pic, currentX, currentY)) {
90 } else if (CheckRightIsFin(pic, currentX, currentY))
94 calledTurnedAround = true;
98 if (pixelIsFin(pic, currentX, currentY)) {
99 if (!calledTurnedAround) {
100 double x = (currentX - startX) * 0.001;
101 double y = (height - currentY - 1) * 0.001;
102 points.add(new Coordinate(x, y));
104 calledTurnedAround = false;
106 } while (currentY < height - 1 && currentY >= 0);
109 private boolean pixelIsFin(BufferedImage pic, int x, int y) {
110 int height = pic.getHeight();
111 int width = pic.getWidth();
113 if ((x >= 0) && (x < width) && (y >= 0) && (y < height)) {
114 int pixel = pic.getRGB(x, y) & 0x00FFFFFF; // Clear alpha, we don't care about it
116 if (pixel == 0) // black is fin
122 private boolean CheckLeftIsFin(BufferedImage pic, int x, int y) {
123 if (facing == FacingDirections.DOWN)
124 return pixelIsFin(pic, x + 1, y);
125 else if (facing == FacingDirections.UP)
126 return pixelIsFin(pic, x - 1, y);
127 else if (facing == FacingDirections.LEFT)
128 return pixelIsFin(pic, x, y + 1);
129 else if (facing == FacingDirections.RIGHT)
130 return pixelIsFin(pic, x, y - 1);
135 private Boolean CheckRightIsFin(BufferedImage pic, int x, int y) {
136 if (facing == FacingDirections.DOWN)
137 return pixelIsFin(pic, x - 1, y);
138 else if (facing == FacingDirections.UP)
139 return pixelIsFin(pic, x + 1, y);
140 else if (facing == FacingDirections.LEFT)
141 return pixelIsFin(pic, x, y - 1);
142 else if (facing == FacingDirections.RIGHT)
143 return pixelIsFin(pic, x, y + 1);
148 private boolean CheckForwardIsFin(BufferedImage pic, int x, int y) {
149 if (facing == FacingDirections.DOWN)
150 return pixelIsFin(pic, x, y + 1);
151 else if (facing == FacingDirections.UP)
152 return pixelIsFin(pic, x, y - 1);
153 else if (facing == FacingDirections.LEFT)
154 return pixelIsFin(pic, x - 1, y);
155 else if (facing == FacingDirections.RIGHT)
156 return pixelIsFin(pic, x + 1, y);
161 private void RotateLeft() {
162 if (facing == FacingDirections.UP)
163 facing = FacingDirections.LEFT;
164 else if (facing == FacingDirections.RIGHT)
165 facing = FacingDirections.UP;
166 else if (facing == FacingDirections.DOWN)
167 facing = FacingDirections.RIGHT;
168 else if (facing == FacingDirections.LEFT)
169 facing = FacingDirections.DOWN;
172 private void RotateRight() {
173 if (facing == FacingDirections.UP)
174 facing = FacingDirections.RIGHT;
175 else if (facing == FacingDirections.RIGHT)
176 facing = FacingDirections.DOWN;
177 else if (facing == FacingDirections.DOWN)
178 facing = FacingDirections.LEFT;
179 else if (facing == FacingDirections.LEFT)
180 facing = FacingDirections.UP;
183 private void MoveForward(BufferedImage pic) {
184 if (facing == FacingDirections.UP) {
187 } else if (facing == FacingDirections.RIGHT) {
188 if (currentX < pic.getWidth() - 1)
190 } else if (facing == FacingDirections.DOWN) {
191 if (currentY < pic.getHeight() - 1)
193 } else if (facing == FacingDirections.LEFT) {
199 private void TurnAround() {
200 if (facing == FacingDirections.UP)
201 facing = FacingDirections.DOWN;
202 else if (facing == FacingDirections.DOWN)
203 facing = FacingDirections.UP;
204 else if (facing == FacingDirections.RIGHT)
205 facing = FacingDirections.LEFT;
206 else if (facing == FacingDirections.LEFT)
207 facing = FacingDirections.RIGHT;
210 private void optimizePoints(ArrayList<Coordinate> points) {
212 ListIterator<Coordinate> start, entry, entry2;
213 Coordinate startPoint, endPoint, testPoint;
216 start = points.listIterator();
217 startPoint = start.next();
218 while ((start.hasNext()) && (startPoint != points.get(points.size() - 1))) {
219 entry = points.listIterator(points.size());
220 endPoint = entry.previous();
221 for (; endPoint != startPoint; endPoint = entry.previous()) {
222 entry2 = points.listIterator(start.nextIndex());
223 testPoint = entry2.next();
224 for (; testPoint != endPoint; testPoint = entry2.next()) {
225 if (pointDistanceFromLine(startPoint, endPoint, testPoint) > 0.001) {
229 if ((testPoint == endPoint) && (endPoint != startPoint)) {
230 // Entire segment was within distance, it's a strait line.
231 // Remove all but the first and last point
232 entry2 = points.listIterator(start.nextIndex());
233 int nextIx = entry2.nextIndex();
234 Coordinate check = entry2.next();
235 while ((entry2.nextIndex() != points.size()) && (check != endPoint)) {
237 nextIx = entry2.nextIndex();
238 check = entry2.next();
241 start = points.listIterator(startIx);
242 startPoint = start.next();
246 if (endPoint == startPoint) {
247 startIx = start.nextIndex();
249 startPoint = start.next();
254 private double pointDistanceFromLine(Coordinate startPoint, Coordinate endPoint, Coordinate testPoint) {
255 Coordinate pt = closestPointOnSegment(startPoint, endPoint, testPoint);
257 return testPoint.sub(pt).length();
260 private Coordinate closestPointOnSegment(Coordinate a, Coordinate b, Coordinate p) {
261 Coordinate D = b.sub(a);
262 double numer = p.sub(a).dot(D);
265 double denom = D.dot(D);
268 return a.add(D.multiply(numer / denom));