392 lines
9.9 KiB
Java
392 lines
9.9 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 java.util.*;
|
|
import viewer.*;
|
|
import viewer.hoese.*;
|
|
import tools.Reporter;
|
|
import gui.SecondoObject;
|
|
|
|
/**
|
|
* A Displayclass for an graph from the graph-algebra
|
|
*/
|
|
public class Dsplgraph extends DisplayGraph implements DisplayComplex
|
|
{
|
|
/** The internal datatype representation */
|
|
String label;
|
|
Vector verticies;
|
|
Vector edges;
|
|
Rectangle2D.Double bounds=null;
|
|
|
|
|
|
private int comparePoints(Point2D.Double p1, Point2D.Double p2){
|
|
if(p1.x<p2.x) return -1;
|
|
if(p1.x>p2.x) return 1;
|
|
if(p1.y<p2.y) return -1;
|
|
if(p1.y>p2.y) return 1;
|
|
return 0;
|
|
}
|
|
|
|
|
|
public void setCategory(Category cat){
|
|
super.setCategory(cat);
|
|
for(int i=0;i<verticies.size();i++){
|
|
((Dsplvertex)(verticies.get(i))).setCategory(cat);
|
|
}
|
|
for(int i=0;i<edges.size();i++){
|
|
((Dspledge)(edges.get(i))).setCategory(cat);
|
|
}
|
|
|
|
}
|
|
|
|
|
|
/**
|
|
* Find out, if the graph is directed. If it is, then not only true is given in the edges hash is also every double edge removed.
|
|
*
|
|
*/
|
|
|
|
private boolean isUndirected()
|
|
{
|
|
if(edges==null){
|
|
return true;
|
|
}
|
|
int size = edges.size();
|
|
|
|
TreeSet tmpedges= new TreeSet(edges);
|
|
Vector newEdges = new Vector(size/2);
|
|
|
|
for(int i=0;i<size;i++){
|
|
Dspledge edge = (Dspledge)edges.get(i);
|
|
Dspledge sEdge = edge.getSymm();
|
|
if(comparePoints(edge.point1,edge.point2)<=0){
|
|
if(!tmpedges.contains(sEdge)){
|
|
return false;
|
|
} else {
|
|
newEdges.add(edge);
|
|
}
|
|
}
|
|
}
|
|
|
|
edges = newEdges;
|
|
return true;
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/** returns always vertices and edges.
|
|
**/
|
|
public Shape getRenderObject(int no, AffineTransform af){
|
|
if(no<verticies.size()){
|
|
return ((Dsplvertex) verticies.get(no)).getRenderObject(0,af);
|
|
} else if(no<verticies.size()+edges.size()) {
|
|
no = no -verticies.size();
|
|
return ((Dspledge)edges.get(no)).getRenderObject(0,af);
|
|
}
|
|
return null;
|
|
}
|
|
|
|
/** draw all Labels
|
|
**/
|
|
public void draw(Graphics g, double time, AffineTransform af){
|
|
|
|
double maxd = Math.min(Math.abs(af.getScaleX()),Math.abs(af.getScaleY()));
|
|
Graphics2D g2 = (Graphics2D) g;
|
|
|
|
Rectangle2D rect = getBounds();
|
|
if(rect==null){
|
|
return;
|
|
}
|
|
double max1 = (maxd*rect.getWidth()/120.0) * (maxd*rect.getHeight())/30;
|
|
max1 = max1/4.0;
|
|
|
|
int max = (int)(max1);
|
|
if(max<verticies.size()){
|
|
return;
|
|
}
|
|
|
|
Color oldC = g.getColor();
|
|
|
|
for(int i=0;i<verticies.size();i++){
|
|
Dsplvertex v = (Dsplvertex) verticies.get(i);
|
|
Layer.drawLabel(v,g,v.getBounds(),time,af,Color.BLUE);
|
|
}
|
|
|
|
max = max - verticies.size();
|
|
if(max<verticies.size()+edges.size()){
|
|
return;
|
|
}
|
|
|
|
for(int i=0;i<edges.size();i++){
|
|
Dspledge e = (Dspledge) edges.get(i);
|
|
|
|
// draw arrow
|
|
if(e.isArrow){
|
|
g2.fill(af.createTransformedShape(e.getArrow(af)));
|
|
}
|
|
|
|
|
|
double d = e.getDirection();
|
|
Rectangle2D r = e.getBounds();
|
|
Point2D.Double p = new Point2D.Double(r.getX() + r.getWidth()/2, r.getY()
|
|
+ r.getHeight()/2);
|
|
|
|
af.transform(p, p);
|
|
|
|
double mx = p.getX();
|
|
double my = p.getY();
|
|
double dx = e.getLabPosOffset().getX();
|
|
double dy = e.getLabPosOffset().getY();
|
|
if(d>=0 && d < 90){
|
|
mx -= dx;
|
|
my += dy;
|
|
} else if(d>=90 && d<180) {
|
|
mx += dx;
|
|
my += dy;
|
|
} else if(d>=180 && d<270){
|
|
mx += dx;
|
|
my -= dy;
|
|
} else {
|
|
mx -=dx;
|
|
my -= dy;
|
|
}
|
|
g2.setPaint(Color.RED);
|
|
String label = e.getLabelText(0);
|
|
dx = g2.getFontMetrics().stringWidth(label) / 2;
|
|
dy = g2.getFontMetrics().getHeight() / 2;
|
|
g2.drawString(e.getLabelText(0), (int)(mx-dx/2),(int)(my+dy));
|
|
|
|
}
|
|
g.setColor(oldC);
|
|
|
|
}
|
|
|
|
|
|
|
|
/** Returns 0. */
|
|
public int numberOfShapes(){
|
|
int shapes = verticies.size() + edges.size();
|
|
return shapes;
|
|
}
|
|
|
|
public boolean isPointType(int no){
|
|
return no<verticies.size();
|
|
}
|
|
|
|
public boolean isLineType(int no){
|
|
return (no>=verticies.size() && ( no < (verticies.size() + edges.size())));
|
|
}
|
|
|
|
|
|
|
|
/**
|
|
* Scans the numeric representation of a point datatype
|
|
*
|
|
* @param v
|
|
* the nestedlist representation of the graph
|
|
*/
|
|
|
|
protected void ScanValue(ListExpr v)
|
|
{
|
|
|
|
int maxLabelLen=5;
|
|
boolean romanNumbers=true;
|
|
Dsplvertex tmp;
|
|
|
|
if(v.listLength()!=2){
|
|
Reporter.writeError("ListLength of the graph type must be two.");
|
|
err=true;
|
|
verticies = null;
|
|
edges = null;
|
|
return;
|
|
}
|
|
|
|
ListExpr VList, EList;
|
|
VList = v.first();
|
|
EList = v.second();
|
|
ListExpr rest = VList;
|
|
|
|
|
|
int vlen = VList.listLength();
|
|
verticies = new Vector(vlen);
|
|
HashMap map = new HashMap(vlen*3);
|
|
|
|
while (!rest.isEmpty())
|
|
{
|
|
// each vertex has to be format (id (xpos, ypos))
|
|
ListExpr V = rest.first();
|
|
if(V.listLength()!=2){
|
|
Reporter.writeError("ListLength of a vertex must be two.");
|
|
err=true;
|
|
verticies = null;
|
|
edges = null;
|
|
return;
|
|
}
|
|
if(V.first().atomType()!=ListExpr.INT_ATOM ||
|
|
V.second().atomType()!=ListExpr.NO_ATOM){
|
|
Reporter.writeError("invalid representation of a vertex found");
|
|
err=true;
|
|
verticies = null;
|
|
edges = null;
|
|
return;
|
|
}
|
|
ListExpr posList = V.second();
|
|
if(posList.listLength()!=2 || posList.first().atomType()!=ListExpr.REAL_ATOM ||
|
|
posList.second().atomType()!=ListExpr.REAL_ATOM){
|
|
Reporter.writeError("invalid representation of a position found");
|
|
err=true;
|
|
verticies = null;
|
|
edges = null;
|
|
return;
|
|
}
|
|
double x = posList.first().realValue();
|
|
double y = posList.second().realValue();
|
|
int id = V.first().intValue();
|
|
|
|
tmp=new Dsplvertex((float)x, (float)y, id);
|
|
verticies.add(tmp);
|
|
|
|
if(tmp.getLabelText(0.0).length()>maxLabelLen) romanNumbers=false;
|
|
if(tmp.getKey()<1)romanNumbers=false;
|
|
if(tmp.getKey()>3999)romanNumbers=false;
|
|
map.put(new Integer(id),new Integer(verticies.size()-1));
|
|
rest = rest.rest();
|
|
}
|
|
if (!romanNumbers)
|
|
{
|
|
Iterator it = verticies.iterator();
|
|
while (it.hasNext()) {
|
|
((Dsplvertex)it.next()).normLabel();
|
|
}
|
|
}
|
|
|
|
rest = EList;
|
|
edges = new Vector(EList.listLength());
|
|
|
|
while (!rest.isEmpty())
|
|
{
|
|
ListExpr edgeList = rest.first();
|
|
if(edgeList.listLength()!=3 ||
|
|
edgeList.first().atomType()!=ListExpr.INT_ATOM ||
|
|
edgeList.second().atomType()!=ListExpr.INT_ATOM ||
|
|
edgeList.third().atomType()!=ListExpr.REAL_ATOM){
|
|
|
|
Reporter.writeError("invalid representation of an egde found");
|
|
err=true;
|
|
verticies = null;
|
|
edges = null;
|
|
return;
|
|
}
|
|
int v1 = edgeList.first().intValue();
|
|
int v2 = edgeList.second().intValue();
|
|
double cost = edgeList.third().realValue();
|
|
Integer V1pos = (Integer)map.get(new Integer(v1));
|
|
Integer V2pos = (Integer)map.get(new Integer(v2));
|
|
if(V1pos==null || V2pos==null){
|
|
Reporter.writeError("edge with invalid node numbers found ("+v1+", "+v2+")");
|
|
err=true;
|
|
verticies = null;
|
|
edges = null;
|
|
return;
|
|
}
|
|
Dsplvertex vert1 = (Dsplvertex)verticies.get(V1pos.intValue());
|
|
Dsplvertex vert2 = (Dsplvertex)verticies.get(V2pos.intValue());
|
|
edges.add(new Dspledge(vert1.getX(),vert1.getY(),vert2.getX(),vert2.getY(),cost));
|
|
rest = rest.rest();
|
|
}
|
|
|
|
if(isUndirected())
|
|
{
|
|
Dspledge tmpe;
|
|
Iterator it = edges.iterator();
|
|
while (it.hasNext()) {
|
|
tmpe=(Dspledge)it.next();
|
|
tmpe.noArrow();
|
|
}
|
|
}
|
|
bounds = computeBounds();
|
|
}
|
|
|
|
|
|
private Rectangle2D.Double computeBounds(){
|
|
Rectangle2D.Double res = null;
|
|
if(verticies==null){
|
|
return res;
|
|
}
|
|
for(int i=0; i< verticies.size();i++)
|
|
{
|
|
Rectangle2D.Double rect = ((Dsplvertex)verticies.get(i)).getBounds();
|
|
if(rect!=null){
|
|
if(res==null){
|
|
res = rect;
|
|
} else{
|
|
res = (Rectangle2D.Double)res.createUnion(rect);
|
|
}
|
|
}
|
|
|
|
}
|
|
return res;
|
|
}
|
|
|
|
/**
|
|
* Gets the bound rectangle of the graph by creating a union of the bounds
|
|
* of all verticies and edges
|
|
*
|
|
* @return The bound rectangle of the graph
|
|
*/
|
|
|
|
public Rectangle2D.Double getBounds()
|
|
{
|
|
return bounds;
|
|
}
|
|
|
|
|
|
/**
|
|
* Init. the Dsplgraph instance.
|
|
*
|
|
* @param type
|
|
* The symbol graph
|
|
* @param value
|
|
* the nestedlist representation of the graph
|
|
* @param qr
|
|
* queryresult to display output.
|
|
*/
|
|
|
|
public void init(String name, int nameWidth, int indent,ListExpr type, ListExpr value, QueryResult qr)
|
|
{
|
|
AttrName = extendString(name,nameWidth, indent);
|
|
ScanValue(value);
|
|
if (err)
|
|
{
|
|
Reporter.writeError("Error in ListExpr :parsing aborted");
|
|
qr.addEntry(new String("(" + AttrName + ": GA(graph))"));
|
|
return;
|
|
} else
|
|
qr.addEntry(this);
|
|
}
|
|
|
|
}
|