001/*
002 * $Id: Rectangle.java 4125 2012-08-19 19:05:22Z kredel $
003 */
004
005package edu.jas.root;
006
007
008import java.io.Serializable;
009
010import edu.jas.arith.BigDecimal;
011import edu.jas.arith.BigRational;
012import edu.jas.arith.Rational;
013import edu.jas.poly.Complex;
014import edu.jas.poly.ComplexRing;
015import edu.jas.structure.ElemFactory;
016import edu.jas.structure.RingElem;
017import edu.jas.structure.GcdRingElem;
018import edu.jas.structure.RingFactory;
019
020
021/**
022 * Rectangle. For example isolating rectangle for complex roots.
023 * @param <C> coefficient type.
024 * @author Heinz Kredel
025 */
026public class Rectangle<C extends RingElem<C> & Rational> implements Serializable {
027
028
029    /**
030     * rectangle corners.
031     */
032    public final Complex<C>[] corners;
033
034
035    /**
036     * Constructor.
037     * @param c array of corners.
038     */
039    @SuppressWarnings("unchecked")
040    /*package*/ Rectangle(Complex<C>[] c) {
041        if (c.length < 5) {
042            corners = (Complex<C>[]) new Complex[5];
043            for (int i = 0; i < 4; i++) {
044                corners[i] = c[i];
045            }
046        } else {
047            corners = c;
048        }
049        if (corners[4] == null) {
050            corners[4] = corners[0];
051        }
052    }
053
054
055    /**
056     * Constructor.
057     * @param mid corner.
058     */
059    @SuppressWarnings("unchecked")
060    public Rectangle(Complex<C> mid) {
061        this(mid, mid);
062    }
063
064
065    /**
066     * Constructor.
067     * @param sw corner.
068     * @param ne corner.
069     */
070    @SuppressWarnings("unchecked")
071    public Rectangle(Complex<C> sw, Complex<C> ne) {
072        this(new Complex<C>(sw.ring, sw.getRe(), ne.getIm()), sw, new Complex<C>(sw.ring, ne.getRe(),
073                        sw.getIm()), ne);
074    }
075
076
077    /**
078     * Constructor.
079     * <pre>
080     *  nw|0 ne|3
081     *  sw|1 se|2
082     * </pre>
083     * @param nw corner.
084     * @param sw corner.
085     * @param se corner.
086     * @param ne corner.
087     */
088    @SuppressWarnings("unchecked")
089    public Rectangle(Complex<C> nw, Complex<C> sw, Complex<C> se, Complex<C> ne) {
090        this((Complex<C>[]) new Complex[] { nw, sw, se, ne });
091    }
092
093
094    /**
095     * String representation of Rectangle.
096     * @see java.lang.Object#toString()
097     */
098    @Override
099    public String toString() {
100        //return "[" + corners[0] + ", " + corners[1] + ", " + corners[2] + ", " + corners[3] + "]";
101        return "[" + corners[1] + ", " + corners[3] + "]";
102        //return centerApprox() + " = [" + corners[0] + ", " + corners[1] + ", " + corners[2] + ", " + corners[3] + "]";
103    }
104
105
106    /**
107     * Get a scripting compatible string representation.
108     * @return script compatible representation for this Rectangle.
109     */
110    public String toScript() {
111        // Python case
112        //return "(" + corners[0] + ", " + corners[1] + ", " + corners[2] + ", " + corners[3] + ")";
113        return "(" + corners[1].toScript() + ", " + corners[3].toScript() + ")";
114    }
115
116
117    /**
118     * Get north west corner.
119     * @return north west corner of this rectangle.
120     */
121    public Complex<C> getNW() {
122        return corners[0];
123    }
124
125
126    /**
127     * Get south west corner.
128     * @return south west corner of this rectangle.
129     */
130    public Complex<C> getSW() {
131        return corners[1];
132    }
133
134
135    /**
136     * Get south east corner.
137     * @return south east corner of this rectangle.
138     */
139    public Complex<C> getSE() {
140        return corners[2];
141    }
142
143
144    /**
145     * Get north east corner.
146     * @return north east corner of this rectangle.
147     */
148    public Complex<C> getNE() {
149        return corners[3];
150    }
151
152
153    /**
154     * Exchange NW corner.
155     * @param c new NW corner.
156     * @return rectangle with north west corner c of this rectangle.
157     */
158    public Rectangle<C> exchangeNW(Complex<C> c) {
159        Complex<C> d = getSE();
160        Complex<C> sw = new Complex<C>(c.factory(), c.getRe(), d.getIm());
161        Complex<C> ne = new Complex<C>(c.factory(), d.getRe(), c.getIm());
162        return new Rectangle<C>(c, sw, d, ne);
163    }
164
165
166    /**
167     * Exchange SW corner.
168     * @param c new SW corner.
169     * @return rectangle with south west corner c of this rectangle.
170     */
171    public Rectangle<C> exchangeSW(Complex<C> c) {
172        Complex<C> d = getNE();
173        Complex<C> nw = new Complex<C>(c.factory(), c.getRe(), d.getIm());
174        Complex<C> se = new Complex<C>(c.factory(), d.getRe(), c.getIm());
175        return new Rectangle<C>(nw, c, se, d);
176    }
177
178
179    /**
180     * Exchange SE corner.
181     * @param c new SE corner.
182     * @return rectangle with south east corner c of this rectangle.
183     */
184    public Rectangle<C> exchangeSE(Complex<C> c) {
185        Complex<C> d = getNW();
186        Complex<C> sw = new Complex<C>(c.factory(), d.getRe(), c.getIm());
187        Complex<C> ne = new Complex<C>(c.factory(), c.getRe(), d.getIm());
188        return new Rectangle<C>(d, sw, c, ne);
189    }
190
191
192    /**
193     * Exchange NE corner.
194     * @param c new NE corner.
195     * @return rectangle with north east corner c of this rectangle.
196     */
197    public Rectangle<C> exchangeNE(Complex<C> c) {
198        Complex<C> d = getSW();
199        Complex<C> nw = new Complex<C>(c.factory(), d.getRe(), c.getIm());
200        Complex<C> se = new Complex<C>(c.factory(), c.getRe(), d.getIm());
201        return new Rectangle<C>(nw, d, se, c);
202    }
203
204
205    /**
206     * Contains a point.
207     * @param c point.
208     * @return true if c is contained in this rectangle, else false.
209     */
210    public boolean contains(Complex<C> c) {
211        Complex<C> ll = getSW();
212        Complex<C> ur = getNE(); // ?? Fix ?? getSW();
213        C cre = c.getRe();
214        C cim = c.getIm();
215        return    cre.compareTo(ll.getRe()) >= 0 && cim.compareTo(ll.getIm()) >= 0
216               && cre.compareTo(ur.getRe()) <= 0 && cim.compareTo(ur.getIm()) <= 0;
217    }
218
219
220    /**
221     * Contains a rectangle.
222     * @param r rectangle.
223     * @return true if r is contained in this rectangle, else false.
224     */
225    public boolean contains(Rectangle<C> r) {
226        return contains(r.getSW()) && contains(r.getNE()); // && contains(r.getSE()) && contains(r.getNW())
227    }
228
229
230    /**
231     * Random point of recatangle.
232     * @return a random point contained in this rectangle.
233     */
234    public Complex<C> randomPoint() {
235        Complex<C> sw = getSW();
236        Complex<C> se = getSE();
237        Complex<C> nw = getNW();
238        Complex<C> r = sw.factory().random(13);
239        C dr = se.getRe().subtract(sw.getRe()); // >= 0
240        C di = nw.getIm().subtract(sw.getIm()); // >= 0
241        C rr = r.getRe().abs();
242        C ri = r.getIm().abs();
243        C one = ((RingFactory<C>) dr.factory()).getONE();
244        if (!rr.isZERO()) {
245            if (rr.compareTo(one) > 0) {
246                rr = rr.inverse();
247            }
248        }
249        if (!ri.isZERO()) {
250            if (ri.compareTo(one) > 0) {
251                ri = ri.inverse();
252            }
253        }
254        // 0 <= rr, ri <= 1
255        rr = rr.multiply(dr);
256        ri = ri.multiply(di);
257        Complex<C> rp = new Complex<C>(sw.factory(), rr, ri);
258        //System.out.println("rp = " + rp);
259        rp = sw.sum(rp);
260        return rp;
261    }
262
263
264    /**
265     * Copy this.
266     * @return a copy of this.
267     */
268    public Rectangle<C> copy() {
269        return new Rectangle<C>(corners);
270    }
271
272
273    /**
274     * Comparison with any other object.
275     * @see java.lang.Object#equals(java.lang.Object)
276     */
277    @Override
278    @SuppressWarnings("unchecked")
279    public boolean equals(Object b) {
280        if (!(b instanceof Rectangle)) {
281            return false;
282        }
283        Rectangle<C> a = null;
284        try {
285            a = (Rectangle<C>) b;
286        } catch (ClassCastException e) {
287        }
288        for (int i = 0; i < 4; i++) {
289            if (!corners[i].equals(a.corners[i])) {
290                return false;
291            }
292        }
293        return true;
294    }
295
296
297    /**
298     * Hash code for this Rectangle.
299     * @see java.lang.Object#hashCode()
300     */
301    @Override
302    public int hashCode() {
303        int hc = 0;
304        for (int i = 0; i < 3; i++) {
305            hc += 37 * corners[i].hashCode();
306        }
307        return 37 * hc + corners[3].hashCode();
308    }
309
310
311    /**
312     * Complex center.
313     * @return r + i m of the center.
314     */
315    public Complex<C> getCenter() {
316        C r = corners[2].getRe().subtract(corners[1].getRe());
317        C m = corners[0].getIm().subtract(corners[1].getIm());
318        ElemFactory<C> rf = r.factory();
319        C two = rf.fromInteger(2);
320        r = r.divide(two);
321        m = m.divide(two);
322        r = corners[1].getRe().sum(r);
323        m = corners[1].getIm().sum(m);
324        return new Complex<C>(corners[0].factory(), r, m);
325    }
326
327
328    /**
329     * Complex of BigRational approximation of center.
330     * @return r + i m as rational approximation of the center.
331     */
332    public Complex<BigRational> getRationalCenter() {
333        Complex<C> cm = getCenter();
334        BigRational rs = cm.getRe().getRational();
335        BigRational ms = cm.getIm().getRational();
336        ComplexRing<BigRational> cf = new ComplexRing<BigRational>(rs.factory());
337        Complex<BigRational> c = new Complex<BigRational>(cf, rs, ms);
338        return c;
339    }
340
341
342    /**
343     * Complex of BigDecimal approximation of center.
344     * @return r + i m as decimal approximation of the center.
345     */
346    public Complex<BigDecimal> getDecimalCenter() {
347        Complex<BigRational> rc = getRationalCenter();
348        BigDecimal rd = new BigDecimal(rc.getRe());
349        BigDecimal md = new BigDecimal(rc.getIm());
350        ComplexRing<BigDecimal> cf = new ComplexRing<BigDecimal>(rd.factory());
351        Complex<BigDecimal> c = new Complex<BigDecimal>(cf, rd, md);
352        return c;
353    }
354
355
356    /**
357     * Approximation of center.
358     * @return r + i m as string of decimal approximation of the center.
359     */
360    public String centerApprox() {
361        Complex<BigDecimal> c = getDecimalCenter();
362        StringBuffer s = new StringBuffer();
363        s.append("[ ");
364        s.append(c.getRe().toString());
365        s.append(" i ");
366        s.append(c.getIm().toString());
367        s.append(" ]");
368        return s.toString();
369    }
370
371
372    /**
373     * Length.
374     * @return |ne-sw|**2;
375     */
376    public C length() {
377        Complex<C> m = corners[3].subtract(corners[1]);
378        return m.norm().getRe();
379    }
380
381
382    /**
383     * Rational Length.
384     * @return rational(|ne-sw|**2);
385     */
386    public BigRational rationalLength() {
387        //BigRational r = new BigRational(length().toString());
388        return length().getRational();
389    }
390
391
392    /**
393     * Length real side.
394     * @return |re(ne)-re(sw)|;
395     */
396    public C lengthReal() {
397        C m = corners[3].getRe().subtract(corners[1].getRe());
398        return m.abs();
399    }
400
401
402    /**
403     * Length imaginary side.
404     * @return |im(ne)-im(sw)|;
405     */
406    public C lengthImag() {
407        C m = corners[3].getIm().subtract(corners[1].getIm());
408        return m.abs();
409    }
410
411}