View Javadoc
1   package com.github.celldynamics.quimp.plugin.utils;
2   
3   import java.awt.Point;
4   import java.awt.geom.Point2D;
5   import java.util.ArrayList;
6   import java.util.Collection;
7   import java.util.List;
8   
9   import org.scijava.vecmath.Point2d;
10  import org.scijava.vecmath.Tuple2d;
11  
12  import com.github.celldynamics.quimp.BoaException;
13  import com.github.celldynamics.quimp.Outline;
14  import com.github.celldynamics.quimp.Shape;
15  import com.github.celldynamics.quimp.Snake;
16  
17  import ij.util.Tools;
18  
19  /**
20   * Perform conversions among Snake, List and xc, yc arrays.
21   * 
22   * <p>As this object returns references to arrays and list, any modification done "in place" on
23   * returned data will affect future conversions done by calling accessor methods.
24   * 
25   * <p>The base format are two arrays xc and yc. All other inputs are converted to arrays
26   * first.
27   * Conversion e.g. Snake->Snake causes that output Snake is not reference of input one because input
28   * has been converted to arrays first.
29   * 
30   * @author p.baniukiewicz
31   * 
32   */
33  public class QuimpDataConverter {
34  
35    private double[] xc; // extracted x coords from Vec2d
36    private double[] yc; // extracted y coords from Vec2d
37  
38    /**
39     * Default constructor.
40     */
41    public QuimpDataConverter() {
42      xc = new double[0];
43      yc = new double[0];
44    }
45  
46    /**
47     * Default constructor if Node list is in form of List.
48     * 
49     * @param input list of vertices. If input is null xc and yc are set to 0 length arrays,
50     *        Snake is
51     *        null then
52     */
53    public QuimpDataConverter(final List<? extends Tuple2d> input) {
54      this();
55      if (input != null) {
56        toArrays(input);
57      }
58    }
59  
60    /**
61     * Default constructor collection of awt.Point.
62     * 
63     * @param input list of vertices. If input is null xc and yc are set to 0 length arrays,
64     *        Snake is null then
65     */
66    public QuimpDataConverter(final Collection<? extends Point2D> input) {
67      this();
68      if (input != null) {
69        toArrays(input);
70      }
71    }
72  
73    /**
74     * Default if Node list is in form of two arrays with coordinates.
75     * 
76     * @param x input list of vertices
77     * @param y input list of vertices
78     */
79    public QuimpDataConverter(final double[] x, final double[] y) {
80      this();
81      if (x.length != y.length) {
82        throw new IllegalArgumentException("Arrays have different lengths");
83      }
84      this.xc = x;
85      this.yc = y;
86    }
87  
88    /**
89     * Default if Node list is in form of two arrays with coordinates.
90     * 
91     * @param x input list of vertices
92     * @param y input list of vertices
93     */
94    public QuimpDataConverter(final float[] x, final float[] y) {
95      this();
96      if (x.length != y.length) {
97        throw new IllegalArgumentException("Arrays have different lengths");
98      }
99      this.xc = Tools.toDouble(x);
100     this.yc = Tools.toDouble(y);
101   }
102 
103   /**
104    * Default constructor if Node list is in form of Snake object.
105    * 
106    * @param s Shape to be converted. If null xc and yc are set to 0 length arrays, List is
107    *        also 0 length.
108    */
109   public QuimpDataConverter(final Shape<?> s) {
110     this();
111     if (s != null) {
112       toArrays(s.asList());
113     }
114   }
115 
116   /**
117    * Converts Vector2d to xc and yc arrays storing xc and yc coordinates of
118    * Vector2d separately.
119    * 
120    * @param input List to be converted to arrays
121    */
122   private void toArrays(final List<? extends Tuple2d> input) {
123     int i = 0;
124     if (input != null) {
125       xc = new double[input.size()];
126       yc = new double[input.size()];
127       for (Tuple2d el : input) {
128         xc[i] = el.getX();
129         yc[i] = el.getY();
130         i++;
131       }
132     } else {
133       xc = new double[0];
134       yc = new double[0];
135     }
136   }
137 
138   /**
139    * Converts awt.Point to xc and yc arrays storing xc and yc coordinates of
140    * Vector2d separately.
141    * 
142    * @param input List to be converted to arrays
143    */
144   private void toArrays(final Collection<? extends Point2D> input) {
145     int i = 0;
146     if (input != null) {
147       xc = new double[input.size()];
148       yc = new double[input.size()];
149       for (Point2D el : input) {
150         xc[i] = el.getX();
151         yc[i] = el.getY();
152         i++;
153       }
154     } else {
155       xc = new double[0];
156       yc = new double[0];
157     }
158   }
159 
160   /**
161    * Data accessor.
162    * 
163    * @return Array with ordered xc coordinates of input list. Array can have 0 length.
164    */
165   public double[] getX() {
166     return xc;
167   }
168 
169   /**
170    * Data accessor.
171    * 
172    * @return Array with ordered yc coordinates of input list. Array can have 0 length.
173    */
174   public double[] getY() {
175     return yc;
176   }
177 
178   /**
179    * Data accessor.
180    * 
181    * <p><b>Warning</b>
182    * 
183    * <p>If user modifies this list this object loses its consistency
184    * 
185    * <p>To convert {@link Shape} to list use {@link Shape#asList()}.
186    * 
187    * @return List of Point2d from stored objects
188    */
189   public List<Point2d> getList() {
190     ArrayList<Point2d> list = new ArrayList<>();
191     for (int i = 0; i < xc.length; i++) {
192       list.add(new Point2d(xc[i], yc[i]));
193     }
194     return list;
195   }
196 
197   /**
198    * Data accessor.
199    * 
200    * <p><b>Warning</b>
201    * 
202    * <p>If user modifies this list this object loses its consistency
203    * 
204    * <p>To convert {@link Shape} to list use {@link Shape#asList()}.
205    * 
206    * @return List of awt.Points from stored objects. Note that points are converted to int
207    */
208   public List<Point2D> getListofIntPoints() {
209     ArrayList<Point2D> list = new ArrayList<>();
210     for (int i = 0; i < xc.length; i++) {
211       list.add(new Point((int) Math.round(xc[i]), (int) Math.round(yc[i])));
212     }
213     return list;
214   }
215 
216   /**
217    * Data accessor.
218    * 
219    * <p><b>Warning</b>
220    * 
221    * <p>If user modifies this list this object loses its consistency
222    * 
223    * <p>To convert {@link Shape} to list use {@link Shape#asList()}.
224    * 
225    * @return List of awt.Points from stored objects. Note that points are converted to int
226    */
227   public List<Point2D> getListofDoublePoints() {
228     ArrayList<Point2D> list = new ArrayList<>();
229     for (int i = 0; i < xc.length; i++) {
230       list.add(new Point2D.Double(xc[i], yc[i]));
231     }
232     return list;
233   }
234 
235   /**
236    * Data accessor.
237    * 
238    * @return Array with ordered xc coordinates of input list as float
239    */
240   public float[] getFloatX() {
241     float[] xf = new float[xc.length];
242     for (int i = 0; i < xc.length; i++) {
243       xf[i] = (float) xc[i];
244     }
245     return xf;
246   }
247 
248   /**
249    * Data accessor.
250    * 
251    * @return Array with ordered yc coordinates of input list as float
252    */
253   public float[] getFloatY() {
254     float[] yf = new float[yc.length];
255     for (int i = 0; i < yc.length; i++) {
256       yf[i] = (float) yc[i];
257     }
258     return yf;
259   }
260 
261   /**
262    * Data accessor.
263    * 
264    * @return Length of input list
265    */
266   public int size() {
267     return xc.length;
268   }
269 
270   /**
271    * Return Snake created from stored data.
272    * 
273    * <p>Head node is first point from list. Snake has centroid, linear coordinates and boundaries
274    * calculated already.
275    * Normals are set according to global BOAState.SegParam#expandSnake.
276    * 
277    * @param id new Id of snake
278    * @return Snake object with Nodes in order of data given on input. Can be null. Normals depend
279    *         on BOA_.qState.segParam.expandSnake
280    * @throws BoaException when there is less than 3 nodes.
281    * @see com.github.celldynamics.quimp.Snake#Snake(double[], double[], int)
282    * @see com.github.celldynamics.quimp.Snake#removeNode(com.github.celldynamics.quimp.Node)
283    * @see Shape#updateNormals(boolean)
284    */
285   public Snake getSnake(int id) throws BoaException {
286     Snake ret = null;
287     if (xc.length == 0 || yc.length == 0) {
288       return ret;
289     } else {
290       ret = new Snake(xc, yc, id);
291       return ret;
292     }
293   }
294 
295   /**
296    * Return Outline created from stored data.
297    * 
298    * <p>Snake has centroid, local curvature and linear coordinates calculated already.
299    * Normals are set <tt>true</tt>
300    * 
301    * @return Outline object with Nodes in order of data given on input. Can be null. Normals are
302    *         set outwards. Head node is first point from list.
303    * @see com.github.celldynamics.quimp.Snake#Snake(double[], double[], int)
304    * @see com.github.celldynamics.quimp.Snake#removeNode(com.github.celldynamics.quimp.Node)
305    * @see Shape#updateNormals(boolean)
306    */
307   public Outline getOutline() {
308     Outline ret = null;
309     if (xc.length == 0 || yc.length == 0) {
310       return ret;
311     } else {
312       ret = new Outline(xc, yc);
313       return ret;
314     }
315   }
316 
317 }