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