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}