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 throw new LocalizedIOException("CustomFinImport.badFinImage");
41 points.add(Coordinate.NUL);
44 // Optimize the loaded fin
47 count = points.size();
48 optimizePoints(points);
49 } while (count != points.size());
55 private boolean validateImage(BufferedImage pic) {
56 int height = pic.getHeight();
57 int width = pic.getWidth();
58 boolean bottomEdgeFound = false;
60 for (int x = 0; x < width; ++x) {
61 for (int y = 0; y < height; ++y) {
62 int pixel = pic.getRGB(x, y) & 0x00FFFFFF; // Clear alpha, we don't care about it
63 // Convert to black & white
64 int red = (pixel & 0x00FF0000) >> 16;
65 int green = (pixel & 0x0000FF00) >> 8;
66 int blue = (pixel & 0x000000FF);
67 pixel = (int)(0.299*red + 0.587*green + 0.114*blue);
69 pixel = 0xFFFFFF; // White
72 pic.setRGB(x, y, pixel);
73 if (y == height - 1) {
75 bottomEdgeFound = true;
82 return bottomEdgeFound;
85 private void loadFin(BufferedImage pic, ArrayList<Coordinate> points) {
86 int height = pic.getHeight();
87 Boolean offBottom = false;
90 currentY = height - 1;
93 if (checkLeftIsFin(pic, currentX, currentY))
95 else if (checkForwardIsFin(pic, currentX, currentY)) {
97 } else if (checkRightIsFin(pic, currentX, currentY))
104 if (currentY < height - 1)
106 if (pixelIsFin(pic, currentX, currentY)) {
107 double x = (currentX - startX) * 0.001;
108 double y = (height - currentY - 1) * 0.001;
109 points.add(new Coordinate(x, y));
111 } while ((!offBottom) || (currentY < height - 1 && currentY >= 0));
114 private boolean pixelIsFin(BufferedImage pic, int x, int y) {
115 int height = pic.getHeight();
116 int width = pic.getWidth();
118 if ((x >= 0) && (x < width) && (y >= 0) && (y < height)) {
119 int pixel = pic.getRGB(x, y) & 0x00FFFFFF; // Clear alpha, we don't care about it
121 if (pixel == 0) // black is fin
127 private boolean checkLeftIsFin(BufferedImage pic, int x, int y) {
128 if (facing == FacingDirections.DOWN)
129 return pixelIsFin(pic, x + 1, y);
130 else if (facing == FacingDirections.UP)
131 return pixelIsFin(pic, x - 1, y);
132 else if (facing == FacingDirections.LEFT)
133 return pixelIsFin(pic, x, y + 1);
134 else if (facing == FacingDirections.RIGHT)
135 return pixelIsFin(pic, x, y - 1);
140 private boolean checkRightIsFin(BufferedImage pic, int x, int y) {
141 if (facing == FacingDirections.DOWN)
142 return pixelIsFin(pic, x - 1, y);
143 else if (facing == FacingDirections.UP)
144 return pixelIsFin(pic, x + 1, y);
145 else if (facing == FacingDirections.LEFT)
146 return pixelIsFin(pic, x, y - 1);
147 else if (facing == FacingDirections.RIGHT)
148 return pixelIsFin(pic, x, y + 1);
153 private boolean checkForwardIsFin(BufferedImage pic, int x, int y) {
154 if (facing == FacingDirections.DOWN)
155 return pixelIsFin(pic, x, y + 1);
156 else if (facing == FacingDirections.UP)
157 return pixelIsFin(pic, x, y - 1);
158 else if (facing == FacingDirections.LEFT)
159 return pixelIsFin(pic, x - 1, y);
160 else if (facing == FacingDirections.RIGHT)
161 return pixelIsFin(pic, x + 1, y);
166 private void rotateLeft() {
167 if (facing == FacingDirections.UP)
168 facing = FacingDirections.LEFT;
169 else if (facing == FacingDirections.RIGHT)
170 facing = FacingDirections.UP;
171 else if (facing == FacingDirections.DOWN)
172 facing = FacingDirections.RIGHT;
173 else if (facing == FacingDirections.LEFT)
174 facing = FacingDirections.DOWN;
177 private void rotateRight() {
178 if (facing == FacingDirections.UP)
179 facing = FacingDirections.RIGHT;
180 else if (facing == FacingDirections.RIGHT)
181 facing = FacingDirections.DOWN;
182 else if (facing == FacingDirections.DOWN)
183 facing = FacingDirections.LEFT;
184 else if (facing == FacingDirections.LEFT)
185 facing = FacingDirections.UP;
188 private void moveForward(BufferedImage pic) {
189 if (facing == FacingDirections.UP) {
192 } else if (facing == FacingDirections.RIGHT) {
193 if (currentX < pic.getWidth() - 1)
195 } else if (facing == FacingDirections.DOWN) {
196 if (currentY < pic.getHeight() - 1)
198 } else if (facing == FacingDirections.LEFT) {
204 private void turnAround() {
205 if (facing == FacingDirections.UP)
206 facing = FacingDirections.DOWN;
207 else if (facing == FacingDirections.DOWN)
208 facing = FacingDirections.UP;
209 else if (facing == FacingDirections.RIGHT)
210 facing = FacingDirections.LEFT;
211 else if (facing == FacingDirections.LEFT)
212 facing = FacingDirections.RIGHT;
215 private void optimizePoints(ArrayList<Coordinate> points) {
217 ListIterator<Coordinate> start, entry, entry2;
218 Coordinate startPoint, endPoint, testPoint;
219 Boolean removedSection;
222 start = points.listIterator();
223 startPoint = start.next();
224 while ((start.hasNext()) && (startPoint != points.get(points.size() - 1))) {
225 removedSection = false;
226 entry = points.listIterator(points.size());
227 endPoint = entry.previous();
228 for (; endPoint != startPoint; endPoint = entry.previous()) {
229 entry2 = points.listIterator(start.nextIndex());
230 testPoint = entry2.next();
231 for (; testPoint != endPoint; testPoint = entry2.next()) {
232 if (pointDistanceFromLine(startPoint, endPoint, testPoint) > 0.0008) {
236 if ((testPoint == endPoint) && (endPoint != startPoint)) {
237 // Entire segment was within distance, it's a strait line.
238 // Remove all but the first and last point
239 entry2 = points.listIterator(start.nextIndex());
240 int nextIx = entry2.nextIndex();
241 Coordinate check = entry2.next();
242 while ((entry2.nextIndex() != points.size()) && (check != endPoint)) {
244 nextIx = entry2.nextIndex();
245 check = entry2.next();
248 start = points.listIterator(startIx);
249 startPoint = start.next();
250 removedSection = true;
254 if ((!removedSection) && (endPoint == startPoint)) {
255 startIx = start.nextIndex();
257 startPoint = start.next();
262 private double pointDistanceFromLine(Coordinate startPoint, Coordinate endPoint, Coordinate testPoint) {
263 Coordinate pt = closestPointOnSegment(startPoint, endPoint, testPoint);
265 return testPoint.sub(pt).length();
268 private Coordinate closestPointOnSegment(Coordinate a, Coordinate b, Coordinate p) {
269 Coordinate D = b.sub(a);
270 double numer = p.sub(a).dot(D);
273 double denom = D.dot(D);
276 return a.add(D.multiply(numer / denom));