Files
secondo/Algebras/Rose/RoseJava/Regions.java
2026-01-23 17:03:45 +08:00

384 lines
10 KiB
Java

import twodsack.io.*;
import twodsack.operation.setoperation.*;
import twodsack.set.*;
import twodsack.setelement.datatype.*;
import twodsack.setelement.datatype.basicdatatype.*;
import twodsack.setelement.datatype.compositetype.*;
import twodsack.util.collection.*;
import twodsack.util.comparator.*;
import java.lang.reflect.*;
import java.io.*;
import java.util.*;
/**
* This class implements the Regions type. A Regions instance consists of a set of polygons which may have holes. A Region can be constructed
* from a set of triangles (which usually is a triangulation of a set of polygons) or a set of segments (which form the polygons' borders).
* Regions instances are one of the three geometic types, which are used as parameter types in the ROSE algebra. The other two are Points and Lines.
*/
public class Regions implements Serializable{
/*
* fields
*/
/**
* Stores the set of triangles of the region.
*/
public TriMultiSet triset = null;
/**
* The bounding box of the Regions object.
*/
private Rect bbox = null;
/**
* If true, a bbox was already computed and is valid.
*/
private boolean bboxDefined = false;
/**
* The area of the Regions object.
*/
public double area = 0.0;
/**
* A flag which indicates, whether the <tt>cycles</tt> of the polygon are defined or not.
*/
private boolean cyclesDefined = false;
/**
* Stores the cycle list, which is a list represenation of the Regions' border.
*/
private CycleListListPoints cycles = null; //the list of cycles
/**
* The Lines object representing the Regions' border.
*/
private Lines border = null;
/**
* True, if the border is computed and valid.
*/
private boolean borderDefined = false;
/*
* constructors
*/
/**
* Constructs an 'empty' Regions value.
*/
public Regions() {
triset = new TriMultiSet(new TriangleComparator());
cyclesDefined = false;
cycles = null;
bbox = null;
area = 0.0;
bboxDefined = false;
border = null;
borderDefined = false;
}
/**
* Constructs a new Regions value from a set of triangles.
* <tt>cyclesDefined</tt> is set to <tt>false</tt>.
*
* @param tl the set of triangles
*/
public Regions(TriMultiSet tl) {
if (tl == null || tl.isEmpty()) {
triset = tl;
cyclesDefined = false;
cycles = null;
bbox = null;
area = 0.0;
bboxDefined = false;
border = null;
borderDefined = false;
}//if
else if(!isRegularTriSet(tl)) {
//throw new RoseAlgebraError("Error in Regions: tried to construct bad Region.");
}//if
else {
triset = TriMultiSet.convert(tl);
cyclesDefined = false;
cycles = null;
bbox = triset.rect();
area = ROSEAlgebra.r_area(this);
bboxDefined = true;
border = new Lines(SupportOps.contour(triset,true,true));
borderDefined = true;
}//else
}
/**
* Constructs a new Regions value from a set of segments.
* <tt>cyclesDefined</tt> is set to <tt>true</tt>.
*
* @param sl the set of segments
*/
public Regions(SegMultiSet sl) {
if (sl == null || sl.isEmpty()) {
triset = new TriMultiSet(new TriangleComparator());
cyclesDefined = false;
cycles = null;
bbox = null;
area = 0.0;
bboxDefined = false;
border = null;
borderDefined = false;
}//if
else {
triset = computeTriSet(sl);
cycles = cyclesPoints();
cyclesDefined = true;
bbox = triset.rect();
area = ROSEAlgebra.r_area(this);
bboxDefined = true;
border = new Lines(SupportOps.contour(triset,true,true));
borderDefined = true;
}//else
}
/**
* Constructs a new Regions value from a Lines value.
* <tt>cyclesDefined</tt> is set to <tt>false</tt>.
*
* @param l the Lines value
*/
public Regions(Lines l) {
if (l.segset.isEmpty()) {
triset = new TriMultiSet(new TriangleComparator());
cyclesDefined = false;
cycles = null;
bbox = null;
area = 0.0;
bboxDefined = false;
border = null;
borderDefined = false;
}//if
else {
triset = computeTriSet(l.segset);
cyclesDefined = false;
cycles = null;
bbox = triset.rect();
area = ROSEAlgebra.r_area(this);
bboxDefined = true;
border = l;
borderDefined = true;
}//else
}
/**
* Constructs a new Regions value from an existing Regions value.
* The triangle set is not copied.
*
* @param r the Regions value
*/
public Regions (Regions r) {
this.triset = r.triset;
this.cyclesDefined = r.cyclesDefined;
this.cycles = r.cycles;
this.area = r.area;
this.bbox = r.bbox;
this.bboxDefined = r.bboxDefined;
this.border = r.border();
this.borderDefined = r.borderDefined;
}
/*
* methods
*/
/**
* Returns the bounding box of the Regions object.
*/
public Rect rect() {
if (bboxDefined)
return bbox;
else {
bbox = triset.rect();
bboxDefined = true;
return bbox;
}//else
}//end method rect
/**
* Computes the triangle set for a given set of segments.
* The passed set of segment must form a proper border for a Regions value.
*
* @param sms the set of segments
*/
private TriMultiSet computeTriSet(SegMultiSet sms) {
//sl must be a regular border of a Regions value
//returns the triangulation of the Region
return Polygons.computeMesh(sms,false);
}//end method computeTriSet
/**
* Returns <tt>true</tt> if the passed set of triangles has no overlapping triangles.
*/
private boolean isRegularTriSet(TriMultiSet tl) {
//returns true if tl doesn't have intersecting triangles
//untested!!!
return true;
/*
Class c = (new Triangle()).getClass();
Class[] paramList = new Class[1];
boolean retVal = false;
try {
paramList[0] = c;
//paramList[0] = Class.forName("Element");
Method m = c.getMethod("pintersects",paramList);
int groupedSize = (SetOps.overlapGroup(tl,m,false)).size();
//System.out.println("R.iRTL: groupedSize: "+groupedSize+", tl.size: "+tl.size());
if (groupedSize == tl.size()) return true;
else { return false; }
}//try
catch (Exception e) {
System.out.println("Exception was thrown in Regions.isRegularTriList(TriList):");
System.out.println("Exception: "+e.getClass()+" --- "+e.getMessage());
System.out.println("Exception Cause: "+e.getCause());
System.out.println("Exception String: "+e.toString());
e.printStackTrace();
System.exit(0);
}//catch
return false;
*/
}//end method isRegularTriSet
/**
* Returns a structure of nested lists that stores points.
* The resulting <tt>CycleListListPoints</tt> stores the vertices of the Regions' cycles. It has a list of points (vertices)
* for every face, the Regions value has. Then, every face consists of an outer cycle (again, it is represented by its border
* points) and its holes. 'Islands' inside of holes are not supported.
*
* @return the nested list that describes the Regions value
*/
public CycleListListPoints cyclesPoints() {
if (this.cyclesDefined) {
return this.cycles;
}//if
else {
Polygons pol = new Polygons(triset);
this.cycles = pol.cyclesPoints();
this.cyclesDefined = true;
return this.cycles;
}//else
}//end method cyclesPoints
/**
* Constructs a Regions value from a byte array.
* Given a byte array (probably from a disk access), a Regions value is constructed from it.
* If the value cannot be restored properly, <tt>null</tt> is returned.
*
* @param buffer the byte array
* @return the restored Regions value
*/
public static Regions readFrom(byte[] buffer){
try{
ObjectInputStream ois = new ObjectInputStream(new ByteArrayInputStream(buffer));
Regions res = (Regions) ois.readObject();
ois.close();
return res;
} catch(Exception e) {
System.out.println("Error in Regions.readFrom(). Cannot restore Regions value properly.");
e.printStackTrace();
}//catch
return null;
}//end method readFrom
/**
* Constructs a serialized Regions value.
* From the Regions value, a byte array is constructed. Then, this array can be written to disk.
*
* @return the byte array
*/
public byte[] writeToByteArray(){
try{
ByteArrayOutputStream byteout = new ByteArrayOutputStream();
ObjectOutputStream objectout = new ObjectOutputStream(byteout);
objectout.writeObject(this);
objectout.flush();
byte[] res = byteout.toByteArray();
objectout.close();
return res;
} catch(Exception e) {
System.out.println("Error in Regions.writeToByteArray: "+e);
e.printStackTrace();
return null; }
}//end method writeToByteArray
/**
* Returs a copy of <tt>this</tt>.
*
* @return the copy
*/
public Regions copy () {
Regions nr = new Regions();
nr.triset = TriMultiSet.convert(this.triset.copy());
nr.cyclesDefined = this.cyclesDefined;
nr.cycles = this.cycles.copy();
nr.border = this.border;
nr.borderDefined = this.borderDefined;
nr.bboxDefined = this.bboxDefined;
nr.bbox = this.bbox;
return nr;
}//end method copy
/**
* Prints the triangle set to standard output.
*/
public void print() {
this.triset.print();
}//end method print
/**
* Compares two Regions objects.
* Returns 0, if both objects are equal.<br>
* Returns 1, if <tt>this</tt> is greater than <tt>p</tt>.<br>
* Returns -1 otherwise.<p>
* Not the Regions objects themselves, but their borders are compared. Thus, the borders are computed and then,
* the Lines objects representing these borders are compared.
*
* @param r the Regions object to compare with
*/
public int compare (Regions r) {
return this.border.compare(r.border());
}//end method compare
/**
* Returns the Regions' border as a Lines object.
* Note, that the border is computed using the SupportOps.contour operations with <tt>minimal = true</tt>
* and <tt>handleCycles = true</tt>.
*
* @return the border
*/
public Lines border () {
if (!borderDefined) {
border = new Lines(SupportOps.contour(triset,true,true));
borderDefined = true;
}//if
return border;
}//end method border
}//end class Regions