Files
2026-01-23 17:03:45 +08:00

554 lines
19 KiB
Java

/*
* RPGConv.java 2005-04-28
*
* Tobias Jacob, part of his bachelor thesis, FernUniversitaet Hagen
* adapted by Dirk Ansorge, FernUniversitaet Hagen
*
*/
package twodsack.io;
import twodsack.set.*;
import twodsack.setelement.datatype.basicdatatype.*;
import twodsack.util.comparator.*;
import twodsack.util.number.*;
import java.io.*;
/**
* The RPGConv class is used to convert data provided in a certain format to the the internal
* format of the 2DSack, i.e. {@link PointMultiSet}, {@link SegMultiSet} and {@link TriMultiSet}. The original data
* is generated by a polygon generator which is able to construct point, segment and polygon
* data.<p>
* Three conversion methods are provided by this class. Additionally, there are two methods to
* check for errors.
*/
public class RPGConv {
/*
* constructors
*/
/**
* Don't use this constructor
*/
private RPGConv(){}
//all data is rounded to 4 digits behind the point
private final static int ROUND_VALUE_DIGITS = 4;
private static boolean success;
private static String errorMsg;
private final static double SCALEFACTOR = 1000000.0;
private final static double SCALEFACTOR2 = 100000.0;
/**
* Returns <tt>true</tt> if the last call of a conversion method was successful.
* <tt>false</tt> otherwise.
*
* @return <tt>true</tt>/<tt>false</tt> depending on the result of the last conversion method
*/
public static boolean lastConversionSuccessful() {
return success;
}//end method lastConversionSuccessful
/**
* Returns the error message returned by the last call of a conversions method.
*
* @return the error message
*/
public static String lastConversionErrorMsg() {
return errorMsg;
}//end method lastConversionErrorMsg
/**
* Reads the region from disk using the fully qualified name of that file.
* The name of this method is a little bit misleading: It does not return
* a regions value, but is able to read one. The regions value is returned
* as set of segments representing the regions' border.
*
* @param rpgFileName the fully qualified file name
* @return the set of segments representing the regions' border
*/
public static SegMultiSet getRegions (String rpgFileName) {
RPGConv.success = true;
RPGConv.errorMsg = "Unknown Error in RPG conversion";
StreamTokenizer st = null;
int token = 0;
SegMultiSet r = new SegMultiSet(new SegmentComparator());
try {
st = new StreamTokenizer (new FileReader (rpgFileName));
st.eolIsSignificant(false);
st.commentChar('#');
//read interval
for (int i = 0; i < 4; i++) {
token = st.nextToken();
}
//read no. of points
token = st.nextToken();
int noOfPoints = 0;
if (token == StreamTokenizer.TT_NUMBER)
noOfPoints = (int) st.nval;
else {
RPGConv.errorMsg = "Error: wrong token type";
throw new Exception();
}
Point[] points = new Point[noOfPoints];
//Point construction
for (int i = 0; i < noOfPoints; i++) {
double x = 0.0;
double y = 0.0;
token = st.nextToken();
if (token == StreamTokenizer.TT_NUMBER)
x = (st.nval*SCALEFACTOR)/SCALEFACTOR2;
else {
RPGConv.errorMsg = "Error: wrong token type";
throw new Exception();
}
token = st.nextToken();
if (token == StreamTokenizer.TT_NUMBER)
y = (st.nval*SCALEFACTOR)/SCALEFACTOR2;
else {
RPGConv.errorMsg = "Error: wrong token type";
throw new Exception();
}
points[i] = new Point (x,y);
}
//read number of Polygons
token = st.nextToken();
if ((token != StreamTokenizer.TT_NUMBER) || (st.nval != 1.0)) {
RPGConv.errorMsg = "File format error";
throw new Exception();
}
//read word "POLYGON"
token = st.nextToken();
if ((token != StreamTokenizer.TT_WORD) || (!st.sval.equals("POLYGON"))) {
RPGConv.errorMsg = "File format error";
throw new Exception();
}
int firstIndex = 0;
int prevIndex = 0;
int actIndex = 0;
//read first point index
token = st.nextToken();
if (token != StreamTokenizer.TT_NUMBER) {
RPGConv.errorMsg = "File format error";
throw new Exception();
}
firstIndex = (int) st.nval;
prevIndex = (int) st.nval;
//read second point index
token = st.nextToken();
if (token != StreamTokenizer.TT_NUMBER) {
RPGConv.errorMsg = "File format error";
throw new Exception();
}
actIndex = (int) st.nval;
int zaehl = 0;
//read further point indices, construct Segments
while (token != StreamTokenizer.TT_EOF) {
//rounding...
points[prevIndex-1].x.round(ROUND_VALUE_DIGITS);
points[prevIndex-1].y.round(ROUND_VALUE_DIGITS);
points[actIndex-1].x.round(ROUND_VALUE_DIGITS);
points[actIndex-1].y.round(ROUND_VALUE_DIGITS);
r.add (new Segment (points[prevIndex - 1], points [actIndex - 1]));
prevIndex = actIndex;
token = st.nextToken();
if ((token != StreamTokenizer.TT_NUMBER) &&
(token != StreamTokenizer.TT_EOF)) {
RPGConv.errorMsg = "File format error";
throw new Exception();
}
if (token != StreamTokenizer.TT_EOF)
actIndex = (int) st.nval;
}
//rounding...
points[actIndex-1].x.round(ROUND_VALUE_DIGITS);
points[actIndex-1].y.round(ROUND_VALUE_DIGITS);
points[firstIndex-1].x.round(ROUND_VALUE_DIGITS);
points[firstIndex-1].y.round(ROUND_VALUE_DIGITS);
r.add (new Segment (points[actIndex - 1], points[firstIndex - 1]));
}catch (Exception e) {
RPGConv.success = false;
if (RPGConv.errorMsg.equals ("Unknown Error in RPG conversion"))
RPGConv.errorMsg = e.getMessage();
try {
while (token != StreamTokenizer.TT_EOF)
token = st.nextToken();
}catch (Exception exc) {}
SegMultiSet reg = new SegMultiSet(new SegmentComparator());
return reg;
}
return r;
}//end method getRegions
/**
* Reads the line value from the disk using the fully qualified name of that file.
* The name of this method is a little bit misleading, since it does not return
* a lines value, but is able to read one. The lines value is returned as a set
* of segments.
*
* @param rpgFileName the fully qualified file name
* @return the set of segments representing the lines value
*/
public static SegMultiSet getLines (String rpgFileName) {
RPGConv.success = true;
RPGConv.errorMsg = "Unknown Error in RPG conversion";
StreamTokenizer st = null;
int token = 0;
SegMultiSet l = new SegMultiSet(new SegmentComparator());
try {
st = new StreamTokenizer (new FileReader (rpgFileName));
st.eolIsSignificant(false);
st.commentChar('#');
//read interval
for (int i = 0; i < 4; i++) {
token = st.nextToken();
}
//read no. of points
token = st.nextToken();
int noOfPoints = 0;
if (token == StreamTokenizer.TT_NUMBER)
noOfPoints = (int) st.nval;
else {
RPGConv.errorMsg = "Error: wrong token type";
throw new Exception();
}
Point[] points = new Point[noOfPoints];
//Point construction
for (int i = 0; i < noOfPoints; i++) {
double x = 0.0;
double y = 0.0;
token = st.nextToken();
if (token == StreamTokenizer.TT_NUMBER) {
x = (st.nval*SCALEFACTOR)/SCALEFACTOR2;
}
else {
RPGConv.errorMsg = "Error: wrong token type";
throw new Exception();
}
token = st.nextToken();
if (token == StreamTokenizer.TT_NUMBER)
y = (st.nval*SCALEFACTOR)/SCALEFACTOR2;
else {
RPGConv.errorMsg = "Error: wrong token type";
throw new Exception();
}
points[i] = new Point (x,y);
}
//read number of Polygons
token = st.nextToken();
if ((token != StreamTokenizer.TT_NUMBER) || (st.nval != 1.0)) {
RPGConv.errorMsg = "File format error";
throw new Exception();
}
//read word "POLYGON"
token = st.nextToken();
if ((token != StreamTokenizer.TT_WORD) || (!st.sval.equals("POLYGON"))) {
RPGConv.errorMsg = "File format error";
throw new Exception();
}
int prevIndex = 0;
int actIndex = 0;
//read first point index
token = st.nextToken();
if (token != StreamTokenizer.TT_NUMBER) {
RPGConv.errorMsg = "File format error";
throw new Exception();
}
prevIndex = (int) st.nval;
//read second point index
token = st.nextToken();
if (token != StreamTokenizer.TT_NUMBER) {
RPGConv.errorMsg = "File format error";
throw new Exception();
}
actIndex = (int) st.nval;
//read further point indices, construct Segments
while (token != StreamTokenizer.TT_EOF) {
//rounding...
points[prevIndex-1].x.round(ROUND_VALUE_DIGITS);
points[prevIndex-1].y.round(ROUND_VALUE_DIGITS);
points[actIndex-1].x.round(ROUND_VALUE_DIGITS);
points[actIndex-1].y.round(ROUND_VALUE_DIGITS);
l.add (new Segment (points[prevIndex - 1], points [actIndex - 1]));
prevIndex = actIndex;
token = st.nextToken();
if ((token != StreamTokenizer.TT_NUMBER) &&
(token != StreamTokenizer.TT_EOF)) {
RPGConv.errorMsg = "File format error";
throw new Exception();
}
if (token != StreamTokenizer.TT_EOF)
actIndex = (int) st.nval;
}
}catch (Exception e) {
RPGConv.success = false;
if (RPGConv.errorMsg.equals ("Unknown Error in RPG conversion"))
RPGConv.errorMsg = e.getMessage();
try {
while (token != StreamTokenizer.TT_EOF)
token = st.nextToken();
}catch (Exception exc) {}
SegMultiSet ln = new SegMultiSet(new SegmentComparator());
return ln;
}
return l;
}//end method getLines
/**
* Reads only some parts of a lines value.
* This method is can be used to read some parts of segments to construct an subset of the
* segments in the file, that has overlapping segments.
*
* @param rpgFileName the fully qualified file name
* @return the set of (partial) segments
*/
public static SegMultiSet getPartsOfLines (String rpgFileName) {
//This method is used in ll_minus.
RPGConv.success = true;
RPGConv.errorMsg = "Unknown Error in RPG conversion";
StreamTokenizer st = null;
int token = 0;
SegMultiSet l = new SegMultiSet(new SegmentComparator());
try {
st = new StreamTokenizer (new FileReader (rpgFileName));
st.eolIsSignificant(false);
st.commentChar('#');
//read interval
for (int i = 0; i < 4; i++) {
token = st.nextToken();
}
//read no. of points
token = st.nextToken();
int noOfPoints = 0;
if (token == StreamTokenizer.TT_NUMBER)
noOfPoints = (int) st.nval;
else {
RPGConv.errorMsg = "Error: wrong token type";
throw new Exception();
}
Point[] points = new Point[noOfPoints];
//Point construction
for (int i = 0; i < noOfPoints; i++) {
double x = 0.0;
double y = 0.0;
token = st.nextToken();
if (token == StreamTokenizer.TT_NUMBER)
x = (st.nval*SCALEFACTOR)/SCALEFACTOR2;
else {
RPGConv.errorMsg = "Error: wrong token type";
throw new Exception();
}
token = st.nextToken();
if (token == StreamTokenizer.TT_NUMBER)
y = (st.nval*SCALEFACTOR)/SCALEFACTOR2;
else {
RPGConv.errorMsg = "Error: wrong token type";
throw new Exception();
}
points[i] = new Point (x,y);
}
//read number of Polygons
token = st.nextToken();
if ((token != StreamTokenizer.TT_NUMBER) || (st.nval != 1.0)) {
RPGConv.errorMsg = "File format error";
throw new Exception();
}
//read word "POLYGON"
token = st.nextToken();
if ((token != StreamTokenizer.TT_WORD) || (!st.sval.equals("POLYGON"))) {
RPGConv.errorMsg = "File format error";
throw new Exception();
}
int prevIndex = 0;
int actIndex = 0;
//read first point index
token = st.nextToken();
if (token != StreamTokenizer.TT_NUMBER) {
RPGConv.errorMsg = "File format error";
throw new Exception();
}
prevIndex = (int) st.nval;
//read second point index
token = st.nextToken();
if (token != StreamTokenizer.TT_NUMBER) {
RPGConv.errorMsg = "File format error";
throw new Exception();
}
actIndex = (int) st.nval;
//read further point indices, construct Segments
byte cnt = 0;
while (token != StreamTokenizer.TT_EOF) {
if (cnt == 0){
Segment helpSegment = new Segment (points[prevIndex - 1], points [actIndex - 1]);
Segment s = null;
Rational zwei = RationalFactory.constRational(2);
if (!(helpSegment.getStartpoint().x.equal
(helpSegment.getEndpoint().x))) {
//non-vertical segment
Rational newX =
(points[prevIndex - 1]).x.plus(((points [actIndex - 1]).x)).dividedby(zwei);
Rational gr = helpSegment.gradient();
Rational newY =
gr.times(newX.minus((points[prevIndex - 1]).x)).plus((points[prevIndex - 1]).y);
//rounding:
points[prevIndex-1].x.round(ROUND_VALUE_DIGITS);
points[prevIndex-1].y.round(ROUND_VALUE_DIGITS);
newX.round(ROUND_VALUE_DIGITS);
newY.round(ROUND_VALUE_DIGITS);
s = new Segment (points[prevIndex - 1], new Point (newX, newY));
} else {
//vertical segment
Rational newY =
(points[prevIndex - 1]).y.plus((points [actIndex - 1]).y).dividedby(zwei);
s = new Segment (points[prevIndex - 1], new Point (points[prevIndex - 1].x, newY));
}
l.add (s);
}
prevIndex = actIndex;
token = st.nextToken();
if ((token != StreamTokenizer.TT_NUMBER) &&
(token != StreamTokenizer.TT_EOF)) {
RPGConv.errorMsg = "File format error";
throw new Exception();
}
if (token != StreamTokenizer.TT_EOF)
actIndex = (int) st.nval;
if (cnt != 2)
cnt++;
else
cnt = 0;
}
}catch (Exception e) {
RPGConv.success = false;
if (RPGConv.errorMsg.equals ("Unknown Error in RPG conversion"))
RPGConv.errorMsg = e.getMessage();
try {
while (token != StreamTokenizer.TT_EOF)
token = st.nextToken();
}catch (Exception exc) {}
SegMultiSet ln = new SegMultiSet(new SegmentComparator());
return ln;
}
return l;
}//end method getPartsOfLines
/**
* Reads the points value from disk using the fully qualified name of that file.
* The name of this method is a little bit misleading, since it does not really
* return a points value. Instead, it reads a points value and returns a
* PointMultiSet.
*
* @param rpgFileName the fully qualified file name
* @return the set of points as a {@link PointMultiSet}
*/
public static PointMultiSet getPoints (String rpgFileName) {
RPGConv.success = true;
RPGConv.errorMsg = "Unknown Error in RPG conversion";
StreamTokenizer st = null;
int token = 0;
PointMultiSet p = new PointMultiSet(new PointComparator());
try {
st = new StreamTokenizer (new FileReader (rpgFileName));
st.eolIsSignificant(false);
st.commentChar('#');
//read interval
for (int i = 0; i < 4; i++) {
token = st.nextToken();
}
//read no. of points
token = st.nextToken();
int noOfPoints = 0;
if (token == StreamTokenizer.TT_NUMBER)
noOfPoints = (int) st.nval;
else {
RPGConv.errorMsg = "Error: wrong token type";
throw new Exception();
}
for (int i = 0; i < noOfPoints; i++) {
double x = 0.0;
double y = 0.0;
token = st.nextToken();
if (token == StreamTokenizer.TT_NUMBER)
x = (st.nval*SCALEFACTOR)/SCALEFACTOR2;
else {
RPGConv.errorMsg = "Error: wrong token type";
throw new Exception();
}
token = st.nextToken();
if (token == StreamTokenizer.TT_NUMBER)
y = (st.nval*SCALEFACTOR)/SCALEFACTOR2;
else {
RPGConv.errorMsg = "Error: wrong token type";
throw new Exception();
}
//rounding...
Rational xRat = RationalFactory.constRational(x);
Rational yRat = RationalFactory.constRational(y);
xRat.round(ROUND_VALUE_DIGITS);
yRat.round(ROUND_VALUE_DIGITS);
p.add(new Point(xRat,yRat));
}
while (token != StreamTokenizer.TT_EOF)
token = st.nextToken();
}catch (Exception e) {
e.printStackTrace();
RPGConv.success = false;
if (RPGConv.errorMsg.equals ("Unknown Error in RPG conversion"))
RPGConv.errorMsg = e.getMessage();
try {
while (token != StreamTokenizer.TT_EOF)
token = st.nextToken();
}catch (Exception exc) {}
PointMultiSet pts = new PointMultiSet(new PointComparator());
return pts;
}
return p;
}//end method getPoints
}//end class RPGConv