001/*
002 * To change this template, choose Tools | Templates
003 * and open the template in the editor.
004 */
005package armyc2.c5isr.graphics2d;
006import java.util.ArrayList;
007import armyc2.c5isr.JavaLineArray.POINT2;
008import armyc2.c5isr.JavaLineArray.ref;
009import armyc2.c5isr.JavaLineArray.arraysupport;
010import armyc2.c5isr.JavaLineArray.lineutility;
011import armyc2.c5isr.JavaLineArray.TacticalLines;
012
013/**
014 *
015*
016 */
017public class BasicStroke implements Stroke {
018
019    /**
020     * Joins path segments by extending their outside edges until they meet.
021     */
022    public final static int JOIN_MITER = 0;
023    /**
024     * Joins path segments by rounding off the corner at a radius of half the
025     * line width.
026     */
027    public final static int JOIN_ROUND = 1;
028    /**
029     * Joins path segments by connecting the outer corners of their wide
030     * outlines with a straight segment.
031     */
032    public final static int JOIN_BEVEL = 2;
033    /**
034     * Ends unclosed subpaths and dash segments with no added decoration.
035     */
036    public final static int CAP_BUTT = 0;
037    /**
038     * Ends unclosed subpaths and dash segments with a round decoration that has
039     * a radius equal to half of the width of the pen.
040     */
041    public final static int CAP_ROUND = 1;
042    /**
043     * Ends unclosed subpaths and dash segments with a square projection that
044     * extends beyond the end of the segment to a distance equal to half of the
045     * line width.
046     */
047    public final static int CAP_SQUARE = 2;
048    float width;
049    int join;
050    int cap;
051    float miterlimit;
052    float dash[];
053    float dash_phase;
054
055    public BasicStroke(float width, int cap, int join, float miterlimit,
056            float dash[], float dash_phase) {
057        if (width < 0.0f) {
058            throw new IllegalArgumentException("negative width");
059        }
060        if (cap != CAP_BUTT && cap != CAP_ROUND && cap != CAP_SQUARE) {
061            throw new IllegalArgumentException("illegal end cap value");
062        }
063        if (join == JOIN_MITER) {
064            if (miterlimit < 1.0f) {
065                throw new IllegalArgumentException("miter limit < 1");
066            }
067        } else if (join != JOIN_ROUND && join != JOIN_BEVEL) {
068            throw new IllegalArgumentException("illegal line join value");
069        }
070        if (dash != null) {
071            if (dash_phase < 0.0f) {
072                throw new IllegalArgumentException("negative dash phase");
073            }
074            boolean allzero = true;
075            int n=dash.length;
076            //for (int i = 0; i < dash.length; i++) 
077            for (int i = 0; i < n; i++) 
078            {
079                float d = dash[i];
080                if (d > 0.0) {
081                    allzero = false;
082                } else if (d < 0.0) {
083                    throw new IllegalArgumentException("negative dash length");
084                }
085            }
086            if (allzero) {
087                throw new IllegalArgumentException("dash lengths all zero");
088            }
089        }
090        this.width = width;
091        this.cap = cap;
092        this.join = join;
093        this.miterlimit = miterlimit;
094        if (dash != null) {
095            this.dash = (float[]) dash.clone();
096        }
097        this.dash_phase = dash_phase;
098    }
099
100    public BasicStroke(float width, int cap, int join, float miterlimit) {
101        this(width, cap, join, miterlimit, null, 0.0f);
102    }
103
104    public BasicStroke(float width, int cap, int join) {
105        this(width, cap, join, 10.0f, null, 0.0f);
106    }
107
108    /**
109     * Constructs a solid <code>BasicStroke</code> with the specified line width
110     * and with default values for the cap and join styles.
111     *
112     * @param width
113     * the width of the <code>BasicStroke</code>
114     * @throws IllegalArgumentException
115     * if <code>width</code> is negative
116     */
117    public BasicStroke(float width) {
118        this(width, CAP_SQUARE, JOIN_MITER, 10.0f, null, 0.0f);
119    }
120
121    /**
122     * Constructs a new <code>BasicStroke</code> with defaults for all
123     * attributes. The default attributes are a solid line of width 1.0,
124     * CAP_SQUARE, JOIN_MITER, a miter limit of 10.0.
125     */
126    public BasicStroke() {
127        this(1.0f, CAP_SQUARE, JOIN_MITER, 10.0f, null, 0.0f);
128    }
129
130    /**
131     * Returns a <code>Shape</code> whose interior defines the stroked outline
132     * of a specified <code>Shape</code>.
133     *
134     * @param s
135     * the <code>Shape</code> boundary be stroked
136     * @return the <code>Shape</code> of the stroked outline.
137     */
138    public Shape createStrokedShape(Shape s) {
139        /*
140         * sun.java2d.pipe.RenderingEngine re =
141         * sun.java2d.pipe.RenderingEngine.getInstance(); return
142         * re.createStrokedShape(s, width, cap, join, miterlimit, dash,
143         * dash_phase);
144         */
145        return null;
146    }
147    public Shape createStrokedShape(Polygon poly) {
148        /*
149         * sun.java2d.pipe.RenderingEngine re =
150         * sun.java2d.pipe.RenderingEngine.getInstance(); return
151         * re.createStrokedShape(s, width, cap, join, miterlimit, dash,
152         * dash_phase);
153         */
154        ArrayList<POINT2>pts=poly.getPathIterator(null).getPoints();
155        int j=0;
156        GeneralPath gp=new GeneralPath();
157        POINT2 pt=null;
158        POINT2[]ptsx=new POINT2[pts.size()];
159        int n=pts.size();
160        //for(j=0;j<pts.size();j++)
161        for(j=0;j<n;j++)
162        {
163            pt=pts.get(j);
164            ptsx[j]=pt;
165        }
166        
167        pts=GetInteriorPoints(ptsx,pts.size(), TacticalLines.DEPTH_AREA,this.width);
168        
169        
170        //for(j=0;j<pts.size();j++)
171        for(j=0;j<n;j++)
172        {
173            pt=pts.get(j);
174            if(j==0)
175                gp.moveTo(pt.x, pt.y);
176            else
177                gp.lineTo(pt.x, pt.y);
178        }
179        return gp;
180    }
181
182    public float getLineWidth() {
183        return width;
184    }
185
186    /**
187     * Returns the end cap style.
188     *
189     * @return the end cap style of this <code>BasicStroke</code> as one of the
190     * static <code>int</code> values that define possible end cap
191     * styles.
192     */
193    public int getEndCap() {
194        return cap;
195    }
196
197    public int getLineJoin() {
198        return join;
199    }
200
201    /**
202     * Returns the limit of miter joins.
203     *
204     * @return the limit of miter joins of the <code>BasicStroke</code>.
205     */
206    public float getMiterLimit() {
207        return miterlimit;
208    }
209
210    /**
211     * Returns the array representing the lengths of the dash segments.
212     * Alternate entries in the array represent the user space lengths of the
213     * opaque and transparent segments of the dashes. As the pen moves along the
214     * outline of the <code>Shape</code> to be stroked, the user space distance
215     * that the pen travels is accumulated. The distance value is used to index
216     * into the dash array. The pen is opaque when its current cumulative
217     * distance maps to an even element of the dash array and transparent
218     * otherwise.
219     *
220     * @return the dash array.
221     */
222    public float[] getDashArray() {
223        if (dash == null) {
224            return null;
225        }
226        return (float[]) dash.clone();
227    }
228
229    public float getDashPhase() {
230        return dash_phase;
231    }
232
233    /**
234     * Returns the hashcode for this stroke.
235     *
236     * @return a hash code for this stroke.
237     */
238    public int hashCode() {
239        int hash = Float.floatToIntBits(width);
240        hash = hash * 31 + join;
241        hash = hash * 31 + cap;
242        hash = hash * 31 + Float.floatToIntBits(miterlimit);
243        if (dash != null) {
244            hash = hash * 31 + Float.floatToIntBits(dash_phase);
245            int n=dash.length;
246            //for (int i = 0; i < dash.length; i++) 
247            for (int i = 0; i < n; i++) 
248            {
249                hash = hash * 31 + Float.floatToIntBits(dash[i]);
250            }
251        }
252        return hash;
253    }
254    
255    public static ArrayList<POINT2> GetInteriorPoints(POINT2[] pLinePoints, 
256            int vblCounter, 
257            int lineType, 
258            double dist) {
259        //var j:int=0;
260        int j = 0;
261        //var index:int=-1;
262        int index = -1;
263        //var pt0:POINT2,pt1:POINT2,pt2:POINT2;
264        POINT2 pt0 = null, pt1 = null, pt2 = null;
265        ///var m01:refobj=new refobj(),m12:refobj=new refobj(); //slopes for lines pt0-pt1 and pt1-pt2
266        ref<double[]> m01 = new ref(), m12 = new ref(), m1 = new ref(), m2 = new ref();
267        //var direction:int=-1;
268        int direction = -1;
269        //var array:Array=new Array();
270        //ArrayList<POINT2>array=new ArrayList();
271        //var intersectPt:POINT2=null;
272        POINT2 intersectPt = null;
273        //var m1:refobj=new refobj(),m2:refobj=new refobj();
274        //var intersectPoints:Array=new Array();
275        ArrayList<POINT2> intersectPoints = new ArrayList();
276        //var b01:Number,b12:Number;    //the y intercepts for the lines corresponding to m1,m2 
277        double b01 = 0, b12 = 0;
278        //var dist:Number=10;
279        //double dist = 10;
280        //the first set of interior points
281        //this assumes the area is closed
282        for (j = 0; j < vblCounter; j++) {
283
284            if (j == 0 || j == vblCounter - 1) {
285                //pt0=new POINT2(pLinePoints[vblCounter-2]);
286                //pt1=new POINT2(pLinePoints[0]);
287                //pt2=new POINT2(pLinePoints[1]);
288                pt0 = pLinePoints[vblCounter - 2];
289                pt1 = pLinePoints[0];
290                pt2 = pLinePoints[1];
291            } else {
292                //pt0=new POINT2(pLinePoints[j-1]);
293                //pt1=new POINT2(pLinePoints[j]);
294                //pt2=new POINT2(pLinePoints[j+1]);                                     
295                pt0 = pLinePoints[j - 1];
296                pt1 = pLinePoints[j];
297                pt2 = pLinePoints[j+1];
298            }
299
300            //the interiior points
301            //var pt00:POINT2,pt01:POINT2;
302            //var pt10:POINT2,pt11:POINT2;
303            POINT2 pt00 = null, pt01 = null;
304            POINT2 pt10 = null, pt11 = null;
305
306            index = j - 1;
307            if (index < 0) {
308                index = vblCounter - 1;
309            }
310
311            direction = arraysupport.GetInsideOutsideDouble2(pt0, pt1, pLinePoints, vblCounter, index, lineType);
312            //reverse the directions     since these are interior points
313            //pt00-pt01 will be the interior line inside line pt0-pt1
314            //pt00 is inside pt0, pt01 is inside pt1
315            switch (direction) {
316                case 0:
317                    //direction=1;
318                    pt00 = lineutility.ExtendDirectedLine(pt0, pt1, pt0, 1, dist);
319                    pt01 = lineutility.ExtendDirectedLine(pt0, pt1, pt1, 1, dist);
320                    break;
321                case 1:
322                    //direction=0;
323                    pt00 = lineutility.ExtendDirectedLine(pt0, pt1, pt0, 0, dist);
324                    pt01 = lineutility.ExtendDirectedLine(pt0, pt1, pt1, 0, dist);
325                    break;
326                case 2:
327                    //direction=3;
328                    pt00 = lineutility.ExtendDirectedLine(pt0, pt1, pt0, 3, dist);
329                    pt01 = lineutility.ExtendDirectedLine(pt0, pt1, pt1, 3, dist);
330                    break;
331                case 3:
332                    //direction=2;
333                    pt00 = lineutility.ExtendDirectedLine(pt0, pt1, pt0, 2, dist);
334                    pt01 = lineutility.ExtendDirectedLine(pt0, pt1, pt1, 2, dist);
335                    break;
336            }
337
338            //pt10-pt11 will be the interior line inside line pt1-pt2
339            //pt10 is inside pt1, pt11 is inside pt2
340            index = j;
341            if (j == vblCounter - 1) {
342                index = 0;
343            }
344            direction = arraysupport.GetInsideOutsideDouble2(pt1, pt2, pLinePoints, vblCounter, index, lineType);
345            //reverse the directions     since these are interior points
346            switch (direction) {
347                case 0:
348                    //direction=1;
349                    pt10 = lineutility.ExtendDirectedLine(pt1, pt2, pt1, 1, dist);
350                    pt11 = lineutility.ExtendDirectedLine(pt1, pt2, pt2, 1, dist);
351                    break;
352                case 1:
353                    //direction=0;
354                    pt10 = lineutility.ExtendDirectedLine(pt1, pt2, pt1, 0, dist);
355                    pt11 = lineutility.ExtendDirectedLine(pt1, pt2, pt2, 0, dist);
356                    break;
357                case 2:
358                    //direction=3;
359                    pt10 = lineutility.ExtendDirectedLine(pt1, pt2, pt1, 3, dist);
360                    pt11 = lineutility.ExtendDirectedLine(pt1, pt2, pt2, 3, dist);
361                    break;
362                case 3:
363                    //direction=2;
364                    pt10 = lineutility.ExtendDirectedLine(pt1, pt2, pt1, 2, dist);
365                    pt11 = lineutility.ExtendDirectedLine(pt1, pt2, pt2, 2, dist);
366                    break;
367            }   //end switch
368            //intersectPt=new POINT2(null);
369            //get the intersection of pt01-p00 and pt10-pt11
370            //so it it is the interior intersection of pt0-pt1 and pt1-pt2
371
372            //first handle the case of vertical lines.
373            if (pt0.x == pt1.x && pt1.x == pt2.x) {
374                intersectPt = new POINT2(pt01);
375                intersectPoints.add(intersectPt);
376                continue;
377            }
378            //it's the same situation if the slopes are identical,
379            //simply use pt01 or pt10 since they already uniquely define the intesection
380            lineutility.CalcTrueSlopeDouble2(pt00, pt01, m01);
381            lineutility.CalcTrueSlopeDouble2(pt10, pt11, m12);
382            if (m01.value[0] == m12.value[0]) {
383                intersectPt = new POINT2(pt01);
384                intersectPoints.add(intersectPt);
385                continue;
386            }
387            //now we are assuming a non-trivial intersection
388            //calculate the y-intercepts using y=mx+b (use b=y-mx)
389            b01 = pt01.y - m01.value[0] * pt01.x;
390            b12 = pt11.y - m12.value[0] * pt11.x;
391
392            intersectPt = lineutility.CalcTrueIntersectDouble2(m01.value[0], b01, m12.value[0], b12, 1, 1, 0, 0);
393            intersectPoints.add(intersectPt);
394        }//end for
395        return intersectPoints;
396    }
397}