//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; /** * The displayclass of the Constraint algebras constraint datatype. */ public class Dsplconstraint extends DisplayGraph { /** The internal datatype representation */ Area areaPolygons; Point2D.Double[] arrPoints; Rectangle2D.Double bounds; GeneralPath GPLines; /** Returns the number of shapes **/ public int numberOfShapes(){ return 3; } public boolean isPointType(int num){ return (num==2); } /** Returns true if the render object is a line **/ public boolean isLineType(int num){ return (num==1); } /** * Returns the shape of the objects in order to render it */ public Shape getRenderObject(int num,AffineTransform at){ if(num==0) { return areaPolygons; } else if(num==1){ return GPLines; } else if(num==2){ Area res = null; double ps = Cat.getPointSize(renderAttribute, CurrentState.ActualTime); double pixx = Math.abs(ps/at.getScaleX()); double pixy = Math.abs(ps/at.getScaleY()); for(int i=0; i< arrPoints.length;i++) { Area tmp = null; if(Cat.getPointasRect()) { tmp=(new Area(new Rectangle2D.Double( arrPoints[i].x-pixx/2, arrPoints[i].y-pixy/2,pixx,pixy))); } else { tmp=(new Area(new Ellipse2D.Double( arrPoints[i].x-pixx/2, arrPoints[i].y-pixy/2,pixx,pixy))); } if(res==null){ res = tmp; }else{ res.add(tmp); } } return res; } else { return null; } } /** * Scans the external representation of a constraint datatype */ private void ScanValue (ListExpr v) { boolean correct = true; ListExpr symbolicTuplesNL = v; ListExpr linConstraintsNL; ListExpr oneLinConstraintNL; boolean emptyPolygons = true; boolean emptyLines = true; boolean emptyPoints = true; Vector vecPoints = new Vector(); areaPolygons = new Area(); GPLines = new GeneralPath(GeneralPath.WIND_EVEN_ODD); if(!v.isAtom()) { while(!symbolicTuplesNL.isEmpty()) { linConstraintsNL = symbolicTuplesNL.first(); symbolicTuplesNL = symbolicTuplesNL.rest(); if(!linConstraintsNL.isAtom()) { Shape geoObject; Vector vLinConstraints = new Vector(); int nrOfCEQ = 0; int currentIndex = 0; int firstIndexCEQ = -1; int secondIndexCEQ = -1; while(!linConstraintsNL.isEmpty()) { oneLinConstraintNL = linConstraintsNL.first(); linConstraintsNL = linConstraintsNL.rest(); if(oneLinConstraintNL.listLength() == 4 && oneLinConstraintNL.first().atomType() == ListExpr.REAL_ATOM && oneLinConstraintNL.second().atomType() == ListExpr.REAL_ATOM && oneLinConstraintNL.third().atomType() == ListExpr.REAL_ATOM && oneLinConstraintNL.fourth().atomType() == ListExpr.SYMBOL_ATOM) { Double a1 = LEUtils.readNumeric( oneLinConstraintNL.first()); Double a2 = LEUtils.readNumeric( oneLinConstraintNL.second()); Double b = LEUtils.readNumeric( oneLinConstraintNL.third()); String strOp = oneLinConstraintNL.fourth().symbolValue(); LinearConstraint2D linConstraint = new LinearConstraint2D( a1.doubleValue(), a2.doubleValue(), b.doubleValue(), strOp); vLinConstraints.addElement(linConstraint); if(linConstraint.strOp.equals("eq")) { nrOfCEQ++; if(firstIndexCEQ==-1) { firstIndexCEQ = currentIndex; } else if(secondIndexCEQ==-1) { secondIndexCEQ = currentIndex; } else { // then there are more than 2 EQ-constraints, // what is a contradiction to the normalization! Reporter.writeError("Error: Too many EQ-constraint!"); } } } else { Reporter.writeError("Error: Wrong format"+ " of lin.constraint!"); } currentIndex++; } // The number of eq-constraints determines // the type of the shape: if(nrOfCEQ==0) { // convex polygon: emptyPolygons = false; GeneralPath GPPolygon = new GeneralPath( GeneralPath.WIND_EVEN_ODD); for(int i=0; i < vLinConstraints.size(); i++) { Point2D.Double point; if(i==0) { point = GetIntersectionPoint((LinearConstraint2D) vLinConstraints.lastElement(), (LinearConstraint2D)vLinConstraints.firstElement()); try{ if(!ProjectionManager.project( point.x,point.y,aPoint)){ Reporter.writeError("error in projection at ("+ point.x+", "+point.y+")"); err=true; return; }else{ GPPolygon.moveTo((float)point.x, (float)point.y); } }catch(Exception e){ Reporter.writeError("Error in Projection at ("+ point.x+","+point.y+")"); err=true; return; } } else { point = GetIntersectionPoint( (LinearConstraint2D)vLinConstraints.elementAt(i-1), (LinearConstraint2D)vLinConstraints.elementAt(i)); try{ if(!ProjectionManager.project( point.x,point.y,aPoint)){ Reporter.writeError("error in projection at ("+ point.x+", "+point.y+")"); err=true; return; }else{ GPPolygon.lineTo((float)point.x, (float)point.y); } }catch(Exception e){ Reporter.writeError("Error in Projection at ("+ point.x+","+point.y+")"); err=true; return; } } } GPPolygon.closePath(); areaPolygons.add(new Area(GPPolygon)); } else if(nrOfCEQ==1) { // line segment: emptyLines = false; // the EQ-constraint is the very first Point2D.Double pointFirst = GetIntersectionPoint( (LinearConstraint2D)vLinConstraints.elementAt(0), (LinearConstraint2D)vLinConstraints.elementAt(1)); Point2D.Double pointSecond = GetIntersectionPoint( (LinearConstraint2D)vLinConstraints.elementAt(0), (LinearConstraint2D)vLinConstraints.elementAt(2)); try{ if(!ProjectionManager.project(pointFirst.x, pointFirst.y,aPoint)){ Reporter.writeError("error in projection at ("+ pointFirst.x+", "+pointFirst.y+")"); err=true; return; } else{ GPLines.moveTo((float)pointFirst.x, (float)pointFirst.y); } }catch(Exception e){ Reporter.writeError("Error in Projection at ("+ pointFirst.x+","+pointFirst.y+")"); err=true; return; } try{ if(!ProjectionManager.project(pointSecond.x, pointSecond.y,aPoint)){ Reporter.writeError("error in projection at ("+ pointSecond.x+", "+pointSecond.y+")"); err=true; return; }else{ GPLines.lineTo((float)pointSecond.x, (float)pointSecond.y); } }catch(Exception e){ Reporter.writeError("Error in Projection at ("+ pointSecond.x+","+pointSecond.y+")"); err=true; return; } } else if(nrOfCEQ==2) { // point: emptyPoints = false; Point2D.Double point = GetIntersectionPoint( (LinearConstraint2D)vLinConstraints.elementAt(0), (LinearConstraint2D)vLinConstraints.elementAt(1)); try{ if(!ProjectionManager.project(point.x,point.y,aPoint)){ Reporter.writeError("error in projection at ("+ point.x+", "+point.y+")"); err=true; return; }else{ vecPoints.addElement(point); } }catch(Exception e){ Reporter.writeError("Error in Projection at ("+ point.x+","+point.y+")"); err=true; return; } } else { Reporter.writeError("Error: nrOfCEQ to big!"); } } else { Reporter.writeError("Error: linConstraintsNL is atomic"); } } } else { Reporter.writeError("Error: instance is atomic "+ "(shoud be a list!)"); } if(emptyPolygons) { areaPolygons = null; } if(emptyLines) { GPLines = null; } arrPoints = (Point2D.Double[])vecPoints.toArray( new Point2D.Double[0]); } /** * Init. the Dsplconstraint instance. */ 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(constraint))")); return; } else { qr.addEntry(this); bounds = null; if(areaPolygons!=null) { bounds = new Rectangle2D.Double(); bounds.setRect(areaPolygons.getBounds2D()); } if(GPLines!=null) { if (bounds == null) { bounds = new Rectangle2D.Double(); bounds.setRect(GPLines.getBounds2D()); } else { bounds = (Rectangle2D.Double)bounds.createUnion( GPLines.getBounds2D()); } } for(int i=0; i< arrPoints.length;i++) { if (bounds == null) bounds = new Rectangle2D.Double(arrPoints[i].x, arrPoints[i].y, 0, 0); else bounds = (Rectangle2D.Double)bounds.createUnion( new Rectangle2D.Double(arrPoints[i].x, arrPoints[i].y, 0, 0)); } } } /** Returns the minimum bounding box **/ public Rectangle2D.Double getBounds () { return bounds; } /** * Returns the intersection point of two linear constraints * (seen as equivalation) * Prerequisite: not parallel or equal * (otherwise they woudn't intersection in one point) */ Point2D.Double GetIntersectionPoint( final LinearConstraint2D linConFirst, final LinearConstraint2D linConSecond) { boolean blnIsPoint; Point2D.Double pIntersection; double x, y; try { x = (linConFirst.a2*linConSecond.b- linConSecond.a2*linConFirst.b)/ (linConFirst.a1*linConSecond.a2- linConSecond.a1*linConFirst.a2); y = (linConFirst.a1*linConSecond.b- linConSecond.a1*linConFirst.b)/ (linConFirst.a2*linConSecond.a1- linConSecond.a2*linConFirst.a1); pIntersection = new Point2D.Double(x,y); } catch (Exception e) { Reporter.writeError("Error: GetIntersectionPoint can't compute a "+ "single intersecting point - invalid input (lin. constraints "+ "describes parallel lines)!"); pIntersection = new Point2D.Double(0,0); } return pIntersection; } /** Datastructure for the internal repr. of a lin. constraint **/ class LinearConstraint2D { public double a1; public double a2; public double b; public String strOp; LinearConstraint2D() { a1 = 0; a2 = 0; b = 0; strOp = new String("eq"); } LinearConstraint2D(double a1, double a2, double b, String strOp) { this.a1 = a1; this.a2 = a2; this.b = b; this.strOp = strOp; } } }