001/*
002 * $Id: Rectangle.java 5916 2018-08-29 20:21:02Z 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.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        }
289        for (int i = 0; i < 4; i++) {
290            if (!corners[i].equals(a.corners[i])) {
291                return false;
292            }
293        }
294        return true;
295    }
296
297
298    /**
299     * Hash code for this Rectangle.
300     * @see java.lang.Object#hashCode()
301     */
302    @Override
303    public int hashCode() {
304        int hc = 0;
305        for (int i = 0; i < 3; i++) {
306            hc += 37 * corners[i].hashCode();
307        }
308        return 37 * hc + corners[3].hashCode();
309    }
310
311
312    /**
313     * Complex center.
314     * @return r + i m of the center.
315     */
316    public Complex<C> getCenter() {
317        C r = corners[2].getRe().subtract(corners[1].getRe());
318        C m = corners[0].getIm().subtract(corners[1].getIm());
319        ElemFactory<C> rf = r.factory();
320        C two = rf.fromInteger(2);
321        r = r.divide(two);
322        m = m.divide(two);
323        r = corners[1].getRe().sum(r);
324        m = corners[1].getIm().sum(m);
325        return new Complex<C>(corners[0].factory(), r, m);
326    }
327
328
329    /**
330     * Complex of BigRational approximation of center.
331     * @return r + i m as rational approximation of the center.
332     */
333    public Complex<BigRational> getRationalCenter() {
334        Complex<C> cm = getCenter();
335        BigRational rs = cm.getRe().getRational();
336        BigRational ms = cm.getIm().getRational();
337        ComplexRing<BigRational> cf = new ComplexRing<BigRational>(rs.factory());
338        Complex<BigRational> c = new Complex<BigRational>(cf, rs, ms);
339        return c;
340    }
341
342
343    /**
344     * Complex of BigDecimal approximation of center.
345     * @return r + i m as decimal approximation of the center.
346     */
347    public Complex<BigDecimal> getDecimalCenter() {
348        Complex<BigRational> rc = getRationalCenter();
349        BigDecimal rd = new BigDecimal(rc.getRe());
350        BigDecimal md = new BigDecimal(rc.getIm());
351        ComplexRing<BigDecimal> cf = new ComplexRing<BigDecimal>(rd.factory());
352        Complex<BigDecimal> c = new Complex<BigDecimal>(cf, rd, md);
353        return c;
354    }
355
356
357    /**
358     * Approximation of center.
359     * @return r + i m as string of decimal approximation of the center.
360     */
361    public String centerApprox() {
362        Complex<BigDecimal> c = getDecimalCenter();
363        StringBuffer s = new StringBuffer();
364        s.append("[ ");
365        s.append(c.getRe().toString());
366        s.append(" i ");
367        s.append(c.getIm().toString());
368        s.append(" ]");
369        return s.toString();
370    }
371
372
373    /**
374     * Length.
375     * @return |ne-sw|**2;
376     */
377    public C length() {
378        Complex<C> m = corners[3].subtract(corners[1]);
379        return m.norm().getRe();
380    }
381
382
383    /**
384     * Rational Length.
385     * @return rational(|ne-sw|**2);
386     */
387    public BigRational rationalLength() {
388        //BigRational r = new BigRational(length().toString());
389        return length().getRational();
390    }
391
392
393    /**
394     * Length real side.
395     * @return |re(ne)-re(sw)|;
396     */
397    public C lengthReal() {
398        C m = corners[3].getRe().subtract(corners[1].getRe());
399        return m.abs();
400    }
401
402
403    /**
404     * Length imaginary side.
405     * @return |im(ne)-im(sw)|;
406     */
407    public C lengthImag() {
408        C m = corners[3].getIm().subtract(corners[1].getIm());
409        return m.abs();
410    }
411
412}