//This file is part of SECONDO. //Copyright (C) 2004, University in Hagen, Department of Computer Science, //Database Systems for New Applications. //SECONDO is free software; you can redistribute it and/or modify //it under the terms of the GNU General Public License as published by //the Free Software Foundation; either version 2 of the License, or //(at your option) any later version. //SECONDO is distributed in the hope that it will be useful, //but WITHOUT ANY WARRANTY; without even the implied warranty of //MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the //GNU General Public License for more details. //You should have received a copy of the GNU General Public License //along with SECONDO; if not, write to the Free Software //Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA package fuzzyobjects.composite; import fuzzyobjects.basic.*; import fuzzyobjects.simple.*; import java.util.Vector; import sj.lang.ListExpr; import java.io.*; /** * this class provides a implementation of fuzzy regions * in the X-triangulation * @author Thomas Behr */ public class FRegion implements CompositeObject{ /** the factor of scale */ protected double SF; // factor of scale /** the set of fuzzy triangles */ protected SortedObjects fTs; // the fuzzy triangles /** the Bounding Box */ protected BoundingBox BB = new BoundingBox(); /** returns the bounding box of this region */ public BoundingBox getBoundingBox(){ return BB; } /** returns the number of containing triangles */ public int getSize(){ return fTs.getSize(); } /** returns the triangle at given position */ public fTriangle getTriangleAt(int index){ if(index<0 || index >=fTs.getSize()) return null; return (fTriangle) fTs.get(index); } /* remove all containibng triangles */ public void clear(){ fTs.makeEmpty(); } /** computes the boundinmg box of this region */ private void computeBoundingBox(){ if(fTs.isEmpty()) BB.setBox(0,0,0,0); else{ SimpleObject FT = fTs.get(0); int minX = FT.getMinX(); int minY = FT.getMinY(); int maxX = FT.getMaxX(); int maxY = FT.getMaxY(); int cX,cY; for (int i=1;i maxX) maxX = cX; if(cY > maxY) maxY = cY; } BB.setBox(minX,minY,maxX,maxY); } } /** * creates a new FRegion with given factor of scale */ public FRegion(double scale){ fTs = new SortedObjects(); SF = scale; } /** * creates a new fuzzy Region with factor of scale 1.0 */ public FRegion() { this(1.0); } /** * returns a readable representation of this FRegion */ public String toString(){ return "FRegion (SF="+SF+")\n"+fTs.toString(); } /** returns the factor of scale */ public double getSF(){ return SF;} /** return the dimension of a region, i.e. 2 */ public int getDim(){ return 2; } /** set the factor of scale */ public boolean setSF(double SF){ if(SF>0){ this.SF=SF; return true; } else return false; } /** * add a new fuzzy triangle to this FRegion * returns false if this FRegion allready contains * a fTriangle whith same basic as fT */ public boolean add(fTriangle fT){ boolean first = fTs.isEmpty(); boolean ok = fTs.insert(fT.copy()); if(ok) { // update bounding box if(!first){ int minX = BB.getMinX(); int minY = BB.getMinY(); int maxX = BB.getMaxX(); int maxY = BB.getMaxY(); if(minX>fT.getMinX()) minX = fT.getMinX(); if(minY>fT.getMinY()) minY = fT.getMinY(); if(maxXfT.getMinX()) minX = fT.getMinX(); if(minY>fT.getMinY()) minY = fT.getMinY(); if(maxX0; return ok & fTs.allValid(); } /** * creates a new FTriangle and invokes * overwrite(fTriangle) * if it is valid */ public boolean overwrite( int x1, int y1, double Z1, int x2, int y2, double Z2, int x3, int y3, double Z3 ){ fTriangle FT = new fTriangle(x1,y1,Z1,x2,y2,Z2,x3,y3,Z3); if(Z1==0 & Z2==0 & Z3==0){ BasicPoint P1 = new BasicPoint(x1,y1); BasicPoint P2 = new BasicPoint(x2,y2); BasicPoint P3 = new BasicPoint(x3,y3); delete(new BasicTriangle(P1,P2,P3)); return true; } else{ boolean result= FT.isValid(); if (result) overwrite(FT); return result; } } /** * deletes the fTriangle whith basic BT from this FRegion * returns false if this FRegion not contains a such fTriangle */ public boolean delete(BasicTriangle BT){ boolean ok = fTs.delete(BT); if(ok & ( BT.getMinX()==BB.getMinX() | BT.getMaxX()==BB.getMaxX() | BT.getMinY()==BB.getMinY() | BT.getMaxY()==BB.getMaxY() ) ) computeBoundingBox(); return ok; } /** * is this FRegion equals to FR ? */ public boolean equals(FRegion FR){ boolean ok; if(FR==null){ ok=false; } else if(this==FR) // the same reference ok=true; else ok= SF == FR.SF && fTs.equals(FR.fTs) ; return ok; } /** computes all membershipvalues on (x,y) */ public double[] ZRel(double x, double y) { Vector tmp = new Vector(); Double Z; BasicTriangle[] Bts = BasicTriangle.getTriangles(x,y); fTriangle current; for(int i=0;i currentmin) min = currentmin; } return min; } // minZ /** returns a copy of this FRegion */ public FRegion copy(){ FRegion C = new FRegion(SF); C.fTs = fTs.copy(); C.BB = BB.copy(); return C; } /** contains this FRegion elements ? */ public boolean isEmpty(){ return fTs.isEmpty(); } /************************************************************* Operators *************************************************************/ /** the operator union */ public FRegion union(FRegion With){ return operator(With,UNION); } /** the operator scaled union */ public FRegion scaledUnion(FRegion With){ FRegion result = operator(With,SCALEDUNION); result.norm(); return result; } /** the operator intersection */ public FRegion intersection(FRegion With){ return operator(With,INTERSECTION); } /** the operator scaled intersection */ public FRegion scaledIntersection(FRegion With){ FRegion result = operator(With,SCALEDINTERSECTION); result.norm(); return result; } /** the add-operator */ public FRegion add(FRegion With){ return operator(With,ADD); } /** the operator scaled add */ public FRegion scaledAdd(FRegion With){ FRegion result = operator(With,SCALEDADD); result.norm(); return result; } /** the difference-operator */ public FRegion difference(FRegion With){ return operator(With,SUBTRACT); } /** the operator scaled difference */ public FRegion scaledDifference(FRegion With){ FRegion result = operator(With,SCALEDDIFFERENCE); result.norm(); return result; } /** the alpha-cut of this FRegion */ public FRegion alphaCut(double alpha, boolean strong){ FRegion CutR = new FRegion(SF); fTriangle Current; boolean isValid; double midZ; for(int i=0; ialpha; else isValid = midZ>= alpha; if(isValid) CutR.fTs.insert(Current.copy()); } CutR.computeBoundingBox(); return CutR; } /** computes the area of the basic from this FRegion */ public double basicArea(){ double a = fuzzyobjects.Params.a; double b = fuzzyobjects.Params.b; return (a*b/4)*fTs.getSize(); } /** computes the surface of the 3d-structure of this FRegion */ public double area3D(){ double result =0; for(int i=0;i0) return; result.add(FT); BasicTriangle[] Neightboors = BT.getNeightboors(); for (int i=0;i=0) List.add(Neightboors[i]); }// for all Neightboors if(List.size()>0){ Next = (BasicTriangle) List.get(0); List.remove(0); Current=(fTriangle) fTs.search(Next); } else Current = null; } while( Current!=null); } /** returns the connected components of this FRegion */ public FRegion[] faces(){ if(isEmpty()) return null; Vector tmp = new Vector(); // for the faces ; // use Vector hence number of faces is unknow FRegion Copy = this.copy(); while( ! Copy.isEmpty()){ FRegion nextFace = new FRegion(SF); fTriangle First = (fTriangle) Copy.fTs.get(0); getComponent(First,nextFace); tmp.add(nextFace); Copy = Copy.difference(nextFace); } FRegion[] result = new FRegion[tmp.size()]; for(int i=0;i=max[i]; if(!ready[i]) allready=false; } Vector allSmallest = new Vector(); // the smallest Triangles Vector Numbers = new Vector(); // the positions in Regs while(!allready){ allready=true; allSmallest = new Vector(); Numbers = new Vector(); // search all smallest Triangles fTriangle currentT; BasicTriangle compareT; for(int i=0;i0 is nothing to do } // not the first triangle } // current Reg contains unprocessing triangle(s) } // for all Regs if(!allready){ double Z1=0,Z2=0,Z3=0; BasicTriangle BT = (BasicTriangle) ( (fTriangle) allSmallest.get(0)).basic(); fTriangle CT; for(int i=0;i0 is nothing to do } // not the first triangle } // current Reg contains unprocessing triangle(s) } // for all Regs if(!allready){ double Z1=0,Z2=0,Z3=0; BasicTriangle BT = (BasicTriangle) ((fTriangle) allSmallest.get(0)).basic(); fTriangle CT; for(int i=0;i // exists a Segment S : BP isendpoint of BP and S // is on the Boundary of R BasicPoint[] Neightboors = BP.getNeightboors(); BasicSegment BS; boolean found=false; for(int i=0;i=0 && !used[pos] ) { BasicSegment CurrentB = NextSegments[j]; SimplePath nextPath = new SimplePath(); nextPath.extend(cuts[i]); if(CurrentB.getEP1().equals(cuts[i])) nextPath.extend(CurrentB.getEP2()); else nextPath.extend(CurrentB.getEP1()); used[pos] = true; boolean ready = false; BasicPoint La = nextPath.getLastPoint(); for(int s=0;s0){ newFT = new fTriangle((BasicTriangle) F1.basic(), Z1,Z2,Z3 ); Goal.fTs.insert(newFT); } } } break; case ADD : { if(F1==null) Goal.fTs.insert(F2.copy()); else if(F2==null) Goal.fTs.insert(F1.copy()); else { // both fTriangles are not null Z1 = Math.min(1,F1.getZ1()+F2.getZ1()); Z2 = Math.min(1,F1.getZ2()+F2.getZ2()); Z3 = Math.min(1,F1.getZ3()+F2.getZ3()); newFT = new fTriangle((BasicTriangle) F1.basic(), Z1,Z2,Z3 ); Goal.fTs.insert(newFT); } // else } break; case SUBTRACT :{ if(F1 == null) ; else if(F2==null) Goal.fTs.insert(F1.copy()); else { // both not null Z1 = Math.max(0,F1.getZ1()-F2.getZ1()); Z2 = Math.max(0,F1.getZ2()-F2.getZ2()); Z3 = Math.max(0,F1.getZ3()-F2.getZ3()); if ((Z1+Z2+Z3)>0) { newFT = new fTriangle( (BasicTriangle) F1.basic(),Z1,Z2,Z3); Goal.fTs.insert(newFT); } } } break; case SCALEDUNION :{ fTriangle newTriangle; if (F1==null) newTriangle = new fTriangle( (BasicTriangle) F2.basic(), F2.getZ1()*scale2, F2.getZ2()*scale2, F2.getZ3()*scale2 ); else if (F2==null) newTriangle = new fTriangle( (BasicTriangle) F1.basic(), F1.getZ1()*scale1, F1.getZ2()*scale1, F1.getZ3()*scale1); else { Z1 = Math.max(F1.getZ1()*scale1, F2.getZ1()*scale2); Z2 = Math.max(F1.getZ2()*scale1, F2.getZ2()*scale2); Z3 = Math.max(F1.getZ3()*scale1, F2.getZ3()*scale2); newTriangle = new fTriangle( (BasicTriangle) F1.basic(), Z1,Z2,Z3); } // else Goal.add(newTriangle); } break; // scaled union case SCALEDINTERSECTION : if (F1==null || F2==null) ; else { Z1 = Math.min(F1.getZ1()*scale1, F2.getZ1()*scale2); Z2 = Math.min(F1.getZ2()*scale1, F2.getZ2()*scale2); Z3 = Math.min(F1.getZ3()*scale1, F2.getZ3()*scale2); Goal.add(new fTriangle( (BasicTriangle) F1.basic(), Z1,Z2,Z3)); } break; case SCALEDADD : { if(F1==null) Goal.add(new fTriangle( (BasicTriangle) F2.basic(), F2.getZ1()*scale2, F2.getZ2()*scale2, F2.getZ3()*scale2)); else if(F2==null) Goal.add(new fTriangle( (BasicTriangle) F1.basic(), F1.getZ1()*scale1, F1.getZ2()*scale1, F1.getZ3()*scale1)); else { Goal.add(new fTriangle( (BasicTriangle) F1.basic(), F1.getZ1()*scale1 + F2.getZ1()*scale2 , F1.getZ2()*scale1 + F2.getZ2()*scale2 , F1.getZ3()*scale1 + F2.getZ3()*scale2 )); } } break; case SCALEDDIFFERENCE : { if(F1==null) Goal.add(new fTriangle( (BasicTriangle) F2.basic(), -F2.getZ1()*scale2, -F2.getZ2()*scale2, -F2.getZ3()*scale2)); else if(F2==null) Goal.add(new fTriangle( (BasicTriangle) F1.basic(), F1.getZ1()*scale1, F1.getZ2()*scale1, F1.getZ3()*scale1)); else { Goal.add(new fTriangle( (BasicTriangle) F1.basic(), F1.getZ1()*scale1 - F2.getZ1()*scale2 , F1.getZ2()*scale1 - F2.getZ2()*scale2 , F1.getZ3()*scale1 - F2.getZ3()*scale2 )); } } break; default : System.err.println("operator not implemented"); } // switch } // processElements /** the 'template' for many operators */ protected FRegion operator(FRegion FR, int op){ // a kind of mergesort int my = 0; int fromFR = 0; // already processed int maxMy = fTs.getSize(); // numbers of elements int maxFromFR = FR.fTs.getSize(); FRegion result = new FRegion(1); fTriangle myFirst=null; // the first unprocessed elements fTriangle FRFirst=null; if(maxMy>0) myFirst = (fTriangle) fTs.get(0); if(maxFromFR>0) FRFirst = (fTriangle) FR.fTs.get(0); if (maxMy >0 && maxFromFR>0){ myFirst = (fTriangle) fTs.get(my); FRFirst = (fTriangle) FR.fTs.get(fromFR); int compareResult; while(my 0){ processElements(null,SF,FRFirst,FR.SF,result,op); fromFR++; if(fromFRZmax) Zmax = Current.getMaxZ(); if(Current.getMinZ() 0) Zmin=0; if(Zmax==0 & Zmin==0) fTs.makeEmpty(); else{ double SFnew = Zmax - Zmin; SortedObjects newfTs= new SortedObjects(); double Z1,Z2,Z3; fTriangle fTnew; for(int i=0;i0) newfTs.insert(fTnew); } // for SF = SFnew*SF; fTs = newfTs; } computeBoundingBox(); } /** check wether this FRegions contains BP */ public boolean contains(BasicPoint BP){ return numberOfTriangles(BP)>0; } /** check wether this FRegion contains BS */ public boolean contains(BasicSegment BS){ return numberOfTriangles(BS)>0; } /** check wether this FRegion contains BT */ public boolean contains(BasicTriangle BT){ return fTs.search(BT)!=null; } /*********************************************************** * * * Topology of the basic * * * ***** ****************************************************/ /** this method is helping for basicTopolRelation */ private static void processTriangle( BasicTriangle T,FRegion R1,FRegion R2, M9Int goal){ BasicPoint[] BP = new BasicPoint[3]; boolean onR1,onR2,onBoundary1,onBoundary2; // process points of minimum Triangle BP[0] = T.getCP1(); BP[1] = T.getCP2(); BP[2] = T.getCP3(); for(int i=0;i<3;i++){ onBoundary1 = R1.onBoundary(BP[i]); onBoundary2 = R2.onBoundary(BP[i]); onR1 = R1.contains(BP[i]); onR2 = R2.contains(BP[i]); if(onR1 & onR2){ // else is nothing to do if(onBoundary1) if(onBoundary2) goal.setValue(true,M9Int.BOUNDARY,M9Int.BOUNDARY); else goal.setValue(true,M9Int.BOUNDARY,M9Int.INTERIOR); else if(onBoundary2) goal.setValue(true,M9Int.INTERIOR,M9Int.BOUNDARY); else goal.setValue(true,M9Int.INTERIOR,M9Int.INTERIOR); } // if common Point } // for } // processTriangle /** computes the 9-intersection-matrix for 2 fregions */ M9Int basicTopolRelation(FRegion R2){ M9Int result = new M9Int(); // this holds ever result.setValue(true,M9Int.EXTERIOR,M9Int.EXTERIOR); boolean ready=false; // all checked intersections are true int currentThis=0; int currentR2 = 0; int maxThis = fTs.getSize(); int maxR2 = R2.fTs.getSize(); int compareResult; fTriangle C1,C2; BasicTriangle MinBasic; fTriangle minT=null; BasicPoint[] BP = new BasicPoint[3]; boolean onBoundary1,onBoundary2, onThis,onR2; while( (currentThis0){ result.setValue(true,M9Int.EXTERIOR,M9Int.INTERIOR); currentR2++; minT=C2; } if(compareResult==0){ currentThis++; currentR2++; minT=C1; result.setValue(true,M9Int.INTERIOR,M9Int.INTERIOR); } processTriangle((BasicTriangle) minT.basic(),this,R2,result); } // while if( currentThis *
    *
  • result[0] : the membership-value for the first endpoint of the BasicSegment (maximum of all fSegments * with the same basic as BS
  • *
  • result[1] : the same for the second endpoint
  • *
  • if the length of the result greater then 2 then * exists two crossing fSgements in this region with same * basic as BS. *
      *
    • result[2] where is the cross point
    • *
    • result[3] the membershipvalue over the cross * point
    • *
    *
  • *
*/ double[] getValues(BasicSegment BS){ double[] result; BasicTriangle[] BTs = BS.getTriangles(); // exact 2 Triangles fTriangle FT1 = (fTriangle) fTs.search(BTs[0]); fTriangle FT2 = (fTriangle) fTs.search(BTs[1]); if( FT1==null || FT2==null){ result = new double[2]; if(FT1==null){ if(FT2==null){ result[0] = 0; result[1] = 0; } else{ //FT2!=null result[0] = FT2.Zfkt(BS.getEP1()); result[1] = FT2.Zfkt(BS.getEP2()); } } else{ // FT1!=null result[0] = FT1.Zfkt(BS.getEP1()); result[1] = FT1.Zfkt(BS.getEP2()); } } else{ // both fTriangles exists double Z1_1 = FT1.Zfkt(BS.getEP1()); double Z1_2 = FT1.Zfkt(BS.getEP2()); double Z2_1 = FT2.Zfkt(BS.getEP1()); double Z2_2 = FT2.Zfkt(BS.getEP2()); if( (Z1_1-Z2_1) * (Z1_2-Z2_2)>=0) { // no crossing result = new double[2]; result[0] = Math.max(Z1_1,Z2_1); result[1] = Math.max(Z1_2,Z2_2); } else{ // the segments are crossing result = new double[4]; result[0] = Math.max(Z1_1,Z2_1); result[1] = Math.max(Z1_2,Z2_2); // compute the cross-position double pos = (Z2_1-Z1_1) / (Z1_2-Z1_1-Z2_2+Z2_1); double value = Z1_1 + pos*(Z1_2-Z1_1); result[2] = pos; result[3] = value; } } // else return result; } /** * returns the max value from both segments on given pos * pos must be in [0,1] */ double getMaxValue(BasicSegment BS ,double pos){ if( (pos<0) || (pos >1)) return 0; BasicTriangle[] BTs = BS.getTriangles(); // exact 2 Triangles fTriangle FT1 = (fTriangle) fTs.search(BTs[0]); fTriangle FT2 = (fTriangle) fTs.search(BTs[1]); double Z1_1,Z1_2,Z2_1,Z2_2; // values on the endpoints double V1,V2; //values on given Position if(FT1==null){ Z1_1=0; Z1_2=0; } else{ Z1_1 = FT1.Zfkt(BS.getEP1()); Z1_2 = FT1.Zfkt(BS.getEP2()); } V1 = Z1_1 + pos*(Z1_2-Z1_1); if(FT2==null){ Z2_1=0; Z2_2=0; } else{ Z2_1 = FT2.Zfkt(BS.getEP1()); Z2_2 = FT2.Zfkt(BS.getEP2()); } V2 = Z2_1 + pos*(Z2_2-Z2_1); return Math.max(V1,V2); } /** computes the topological relationship between this and R2 */ public FuzzyTopRel topolRelation(FRegion R2){ FuzzyTopRel result = new FuzzyTopRel(); fTriangle Current; BasicTriangle CurrentBasic; BasicPoint[] Corners; BasicSegment[] Sides; fTriangle FT2; for(int i=0;iZ2_1 & Z1_2>Z2_2 & Z1_3>Z2_3) ) // all over result.computeValue(Z1_1,Z2_1); else if(Z1_1==Z2_1 & Z1_2==Z2_2 & Z1_3==Z2_3) result.computeValue(0.5,0.5); else { // the triangles are crossing; // this covers all cases result.computeValue(0.3,0.7); result.computeValue(0.7,0.3); result.computeValue(0.5,0.5); } } } // for all containing TRiangles return result; } // topolRelation /** compute the topological relationship between this and CO */ public FuzzyTopRel topolRelation(CompositeObject CO){ FuzzyTopRel result; if(CO instanceof FPoint){ result = ((FPoint)CO).topolRelation(this); result.makeSym(); return result; } if(CO instanceof FLine){ result = ((FLine)CO).topolRelation(this); result.makeSym(); return result; } if(CO instanceof FRegion){ return topolRelation((FRegion) CO); } return null; } /** returns the ListExpr representation of this FRegion * (SF , ()) */ public ListExpr toListExpr(){ // first create the SegmentList ListExpr Triangles; ListExpr Last=null; if(fTs.getSize()==0) Triangles = ListExpr.theEmptyList(); else { Triangles = ListExpr.oneElemList( ((fTriangle)fTs.get(0)).toListExpr()); Last = Triangles; } fTriangle NextTriangle; for(int i=1;i*/ public ListExpr toTypedListExpr(){ return ListExpr.twoElemList( ListExpr.symbolAtom("fregion"),toListExpr()); } /** read this FRegion from a ListExpr * @return true if LE is a valid Representaion of a FRegion * all valid Triangles of this List are inserted */ public boolean readFromListExpr(ListExpr LE){ SF = 1.0; fTs.makeEmpty(); computeBoundingBox(); if(LE==null) return false; if(LE.listLength()!=2) return false; ListExpr SFList = LE.first(); if( !( SFList.isAtom() && (SFList.atomType()==ListExpr.INT_ATOM || SFList.atomType()==ListExpr.REAL_ATOM))) return false; double z= SFList.atomType()==ListExpr.INT_ATOM ? SFList.intValue() : SFList.realValue(); if(z<=0) return false; this.SF = z; ListExpr Triangles = LE.second(); fTriangle T; boolean ok = true; while( !Triangles.isEmpty() & ok) { T = new fTriangle(0,0,0,0,0,0,0,0,0); if(T.readFromListExpr(Triangles.first())){ add(T); Triangles=Triangles.rest(); } else ok = false; } return ok; } /** returns a String representation of * the corresponding ListExpr */ public String toListString(){ return toListExpr().writeListExprToString(); } /** read the FRegion from a String representation of a ListExpr * @return true if List is a String of a ListExpr containing * a correct FRegion */ public boolean readFromListString(String List){ ListExpr LE = new ListExpr(); if(LE.readFromString(List)!=0){ return false; } else{ return readFromListExpr(LE); } } /** this method is used for reading a fuzzy region * from a byte array; * returns null if the construction of the object failed */ public static FRegion readFrom(byte[] buffer){ try{ ObjectInputStream ois; ois = new ObjectInputStream(new ByteArrayInputStream(buffer)); FRegion res = (FRegion) ois.readObject(); ois.close(); return res; } catch(Exception e){ return null; } } /** this method serialized an object */ public byte[] writeToByteArray(){ try{ ByteArrayOutputStream byteout; byteout = new ByteArrayOutputStream(fTs.getSize()*16+25); ObjectOutputStream objectout; objectout = new ObjectOutputStream(byteout); objectout.writeObject(this); objectout.flush(); byte[] res = byteout.toByteArray(); objectout.close(); return res; } catch(Exception e){ return null; } } /** computes a hash-value for this FPoint */ public int getHashValue(){ return Math.abs((BB.getMaxX()-BB.getMinX())* (BB.getMaxY()-BB.getMinY())+BB.getMinX() +BB.getMinY()); } // define constants for the operators private static final int UNION = 0; private static final int INTERSECTION=1; private static final int ADD=2; private static final int SUBTRACT=3; private static final int SCALEDUNION=4; private static final int SCALEDINTERSECTION=5; private static final int SCALEDADD=6; private static final int SCALEDDIFFERENCE=7; } // FRegion;