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