Files
secondo/Javagui/viewer/hoese/algebras/Dsplsline.java
2026-01-23 17:03:45 +08:00

412 lines
11 KiB
Java

//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 viewer.hoese.algebras;
import java.awt.geom.*;
import java.awt.*;
import sj.lang.ListExpr;
import viewer.hoese.*;
import java.util.Vector;
import java.util.Iterator;
import java.util.Stack;
import tools.Reporter;
/**
* The displayclass of the sline datatype.
*/
public class Dsplsline extends Dsplline {
private static Area basicArrow;
boolean isArrow = true;
boolean startSmaller;
Point2D.Double p1;
Point2D.Double p2;
public int numberOfShapes(){
return 2;
}
public boolean isLineType(int num){
if (num==0){
return super.isLineType(num);
}
return false; // draw arrow as a region
}
public Shape getRenderObject(int num, AffineTransform at){
if(num==0){
return super.getRenderObject(num,at);
}
if(!isArrow){
return null;
}
if(!err && defined && p1!=null && p2!=null){
return getArrow(at,p1,p2);
}
return null;
}
public static boolean almostEqual(double a, double b){
return Math.abs(a-b) < 0.00000001;
}
public static boolean almostEqual(Point2D.Double p1, Point2D.Double p2){
return almostEqual(p1.x,p2.x) && almostEqual(p1.y,p2.y);
}
public static boolean isLess(Point2D.Double p1, Point2D.Double p2){
if(almostEqual(p1.x,p2.x)){
if(almostEqual(p1.y,p2.y)){
return false;
} else {
return p1.y < p2.y;
}
}
return p1.x < p2.x;
}
public static void reverse(Vector<Point2D.Double > v){
Stack<Point2D.Double> stack = new Stack<Point2D.Double>();
for(int i=0;i<v.size();i++){
stack.push(v.get(i));
}
v.clear();
while(!stack.isEmpty()){
v.add(stack.pop());
}
}
private boolean insertSegment(Vector<Vector<Point2D.Double>> sequences, double x1, double y1, double x2, double y2){
Point2D.Double p1 = new Point2D.Double(x1,y1);
Point2D.Double p2 = new Point2D.Double(x2,y2);
Vector<Vector<Point2D.Double>> connectedSequences = new Vector<Vector<Point2D.Double>>();
Iterator<Vector<Point2D.Double>> it = sequences.iterator();
while(it.hasNext() && connectedSequences.size() < 2){
Vector<Point2D.Double> seq = it.next();
if( almostEqual(seq.get(0),p1) || almostEqual(seq.get(0),p2) ||
almostEqual(seq.get(seq.size()-1), p1) || almostEqual(seq.get(seq.size()-1),p2)){
connectedSequences.add(seq);
}
}
if(connectedSequences.size()==0){ // new unconnected segment
Vector<Point2D.Double> newSeq = new Vector<Point2D.Double>();
newSeq.add(p1);
newSeq.add(p2);
sequences.add(newSeq);
} else { // new segment extends a single sequence
// extend the first sequence by one point
Vector<Point2D.Double> seq = connectedSequences.get(0);
if(almostEqual(p1,seq.get(0))){
seq.add(0,p2);
} else if(almostEqual(p2,seq.get(0))){
seq.add(0,p1);
} else if(almostEqual(p1,seq.get(seq.size()-1))){
seq.add(p2);
} else {
seq.add(p1);
}
if(connectedSequences.size()==2){ // we have to connect both sequences
Vector<Point2D.Double> seq2 = connectedSequences.get(1);
if(almostEqual(seq.get(seq.size()-1), seq2.get(0))){ // seq2 extends seq
sequences.remove(seq2);
seq.addAll(seq2);
} else if(almostEqual(seq2.get(seq2.size()-1),seq.get(0))){ // seq extends seq2
seq2.addAll(seq);
sequences.remove(seq);
} else if( almostEqual(seq.get(seq.size()-1),seq2.get(seq2.size()-1))) { // both endpoints are equal
sequences.remove(seq2);
reverse(seq2);
seq.addAll(seq2);
} else if(almostEqual(seq.get(0),seq2.get(0))){ // both starting points are equal
reverse(seq);
seq.addAll(seq2);
sequences.remove(seq2);
} else { // not a sline
return false;
}
}
}
return true;
}
public void ScanValue(ListExpr value){
if(isUndefined(value)){
defined = false;
GP = null;
return;
}
defined = true;
startSmaller = true;
if(value.listLength()==2 && value.second().atomType()==ListExpr.BOOL_ATOM){// new style
startSmaller = value.second().boolValue();
value = value.first();
}
// try to build a point sequence from the shuffled segments
if(value.isEmpty()){
GP = null;
return;
}
Vector<Vector<Point2D.Double> > pointSequences = new Vector<Vector<Point2D.Double> >();
while(!value.isEmpty()){
ListExpr segment = value.first();
value = value.rest();
if(segment.listLength()!=4){
Reporter.writeError("Error: No correct segment expression: 4 elements needed");
GP=null;
err = true;
return;
}
Double X1 = LEUtils.readNumeric(segment.first());
Double Y1 = LEUtils.readNumeric(segment.second());
Double X2 = LEUtils.readNumeric(segment.third());
Double Y2 = LEUtils.readNumeric(segment.fourth());
if(X1==null || X2==null || Y1==null || Y2==null){
Reporter.writeError("Error: No correct segment expression: 4 elements needed");
GP=null;
err = true;
return;
}
double x1 = X1.doubleValue();
double y1 = Y1.doubleValue();
double x2 = X2.doubleValue();
double y2 = Y2.doubleValue();
// prject the coordinates if possible
try{
if(!ProjectionManager.project(x1,y1,aPoint)){
Reporter.writeError("Error: Problem in projection of coordinates");
GP=null;
err = true;
return;
}
x1 = aPoint.x;
y1 = aPoint.y;
if(!ProjectionManager.project(x2,y2,aPoint)){
Reporter.writeError("Error: Problem in projection of coordinates");
GP=null;
err = true;
return;
}
x2 = aPoint.x;
y2 = aPoint.y;
} catch(Exception e){
Reporter.writeError("Error: No correct segment expression: 4 elements needed");
GP=null;
err = true;
return;
}
if(!insertSegment(pointSequences, x1,y1,x2,y2)){
Reporter.writeError("found problem in reconstructing pointsequence");
}
}
if(pointSequences.size()!=1){
Reporter.writeError("Error: the segments do not form a simple line, no arrow will be drawn");
isArrow = false;
} else {
Vector<Point2D.Double> sequence = pointSequences.get(0);
if(sequence.size()<2){
Reporter.writeError("Error: internal error, found sequnece with less than 2 points");
GP=null;
err = true;
return;
}
if(isCycle(sequence)){
int end = findSmallestIndex(sequence);
int start;
if(startSmaller){
start=end-1;
if(start<0){
start = sequence.size()-1;
}
} else {
start = end+1;
if(start>=sequence.size()){
start=0;
}
}
p1 = sequence.get(start);
p2 = sequence.get(end);
} else {
boolean firstLess = isLess(sequence.get(0) ,
sequence.get(sequence.size()-1));
if(startSmaller == firstLess){
this.p1 = sequence.get(sequence.size()-2);
this.p2 = sequence.get(sequence.size()-1);
} else {
this.p1 = sequence.get(1);
this.p2 = sequence.get(0);
}
}
}
GP = new GeneralPath();
Iterator<Vector<Point2D.Double>> it = pointSequences.iterator();
while(it.hasNext()){
Vector<Point2D.Double> sequence = it.next();
for(int i=0;i<sequence.size(); i++){
Point2D.Double p = sequence.get(i);
if(i==0){
GP.moveTo((float)p.x, (float)p.y);
} else {
GP.lineTo((float)p.x,(float)p.y);
}
}
}
defined = true;
err = false;
}
private static boolean isCycle(Vector<Point2D.Double> s){
if(s.size()<2){
return false;
}
return s.get(0).equals(s.get(s.size()-1));
}
private static int findSmallestIndex(Vector<Point2D.Double> s){
int index = 0;
Point2D.Double p = s.get(0);
for(int i=1;i<s.size();i++){
Point2D.Double p2 = s.get(i);
if(isLess(p2,p)){
index = i;
p = p2;
}
}
return index;
}
private static void resort(Vector<Point2D.Double> sequence){
if(sequence.size()<2){
return;
}
if(! sequence.get(0).equals(sequence.get(sequence.size()-1))){
// not a cycle
return;
}
// cycle found, sort sequence, that the smallest contained point
// is the first one
// part 1 search the index of the smallest point
int index = findSmallestIndex(sequence);
// TODO implement this algorithm without copying vectors
Vector<Point2D.Double> sequenceCopy = new Vector<Point2D.Double>(sequence);
int size = sequence.size();
for(int i=0;i<size;i++){
System.out.println((i+index)%size + "->" + i);
sequence.set(i, sequenceCopy.get((i+index)%size));
}
}
public Shape getArrow(AffineTransform af, Point2D.Double point1, Point2D.Double point2){
createBasicArrow(Cat);
// transform the basicArrow to be in the correct angle at the end of the connection
double x1 = point1.getX();
double x2 = point2.getX();
double y1 = point1.getY();
double y2 = point2.getY();
AffineTransform aat = new AffineTransform();
double sx = af.getScaleX();
double sy = af.getScaleY();
AffineTransform trans = AffineTransform.getTranslateInstance(x2,y2);
aat.concatenate(trans);
// normalize
double dx = x1-x2;
double dy = y1-y2;
double len = Math.sqrt(dx*dx+dy*dy); // the length
dx = dx / len;
dy = dy / len;
AffineTransform Rot = new AffineTransform(dx,dy,-dy,dx,0,0);
aat.concatenate(Rot);
AffineTransform scale = AffineTransform.getScaleInstance(5/sx,5/sy);
aat.concatenate(scale);
Shape S = aat.createTransformedShape(basicArrow);
return S;
}
void createBasicArrow(Category cat){
GeneralPath gparrow = new GeneralPath();
gparrow.moveTo(0,0);
gparrow.lineTo(5,-1);
gparrow.lineTo(3,0);
gparrow.lineTo(5,1);
gparrow.lineTo(0,0);
Shape s = gparrow;
if(cat!=null){
double x = cat.getPointSize(renderAttribute, CurrentState.ActualTime);
if(x>0){
AffineTransform at = AffineTransform.getScaleInstance(x/5,x/5);
s = at.createTransformedShape(gparrow);
} else {
basicArrow=null;
return;
}
}
basicArrow = new Area(s);
}
/** returns the string for the textual representation of this **/
public String toString(){
if(err || !defined){
return entry;
}
else{
return entry + ", " + startSmaller + " ("+Cat.getName()+")";
}
}
}