//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 sj.lang.ListExpr; import viewer.*; import viewer.hoese.*; import java.util.*; import javax.swing.*; import java.awt.*; import javax.swing.border.*; import java.awt.event.*; import java.awt.geom.*; import gui.Environment; import tools.Reporter; /** * A displayclass for the instant-type (spatiotemp algebra), alphanumeric with TimePanel */ public class Dsplmovingreal extends DsplGeneric implements Timed,Function,ExternDisplay,LabelAttribute, RenderAttribute{ protected Interval boundingInterval; protected Vector Intervals = new Vector(10, 5); protected Vector connectedIntervals = null; protected Vector MRealMaps = new Vector(10, 5); protected double PixelTime; protected double min=Double.POSITIVE_INFINITY ; protected double max=Double.NEGATIVE_INFINITY ; protected final static int PSIZE=300; protected boolean err; protected boolean defined; /** format specification for label **/ static java.text.DecimalFormat format = new java.text.DecimalFormat("#.####"); public boolean isExternDisplayed(){ return(functionframe.isVisible() && this.equals(functionframe.getSource())); //return functionframe.isVisible() && functionframe.contains(this); } public void displayExtern(){ if(!defined){ Reporter.showInfo("not defined"); return; } if(boundingInterval!=null){ functionframe.setSource(this); //functionframe.addFunction(this); functionframe.setVisible(true); functionframe.toFront(); } else{ Reporter.showInfo("The moving real is empty"); } } /** This method returns the "bounding box" * of the definition time */ public Interval getBoundingInterval(){ return boundingInterval; } /** * A method of the Timed-Interface to render the content of the TimePanel * @param PixelTime pixel per time unit * @return A JPanel component with the renderer */ public JPanel getTimeRenderer (double PixTime) { if(err) // error return null; if(boundingInterval==null) // empty return null; if(Intervals.size()>500){ if(connectedIntervals==null){ connectedIntervals= TimeRenderer.computeConnectedIntervals(Intervals); } return TimeRenderer.getTimeRenderer(PixTime, connectedIntervals, boundingInterval); } // Create a MRealLabel for each unit and add it to // the panel PixelTime = PixTime; JPanel jp = new JPanel(null); if (Intervals == null) return null; ListIterator li = Intervals.listIterator(); int cnt = 0; while (li.hasNext()) { Interval in = (Interval)li.next(); int start = (int)((in.getStart() - boundingInterval.getStart())*PixelTime); int end = (int)((in.getEnd() - boundingInterval.getStart())*PixelTime); String bs = MRealMaps.elementAt(cnt).toString(); MRealLabel jc = new MRealLabel(bs); jc.ValueIndex = cnt++; jc.setFont(new Font("Dialog", Font.PLAIN, 12)); jc.setOpaque(true); jc.setForeground(Color.black); //jc.setBackground(Color.yellow); jc.setToolTipText("..."); MRealMap mr = (MRealMap)MRealMaps.elementAt(jc.ValueIndex); for (int x=start;x<=end;x++) { double actTime = (double)x/PixelTime+boundingInterval.getStart(); Double Mv = getValueAt(actTime,jc.ValueIndex); if(Mv==null){ Reporter.writeError("Cannot determine the value at"+actTime); }else{ double mv=Mv.doubleValue(); } } // set posittion and size of this label jc.setBounds(start, 0, end - start, PSIZE); // add the label to the panel jp.add(jc); } //jc.setBorder(new MatteBorder(2, (in.isLeftclosed()) ? 2 : 0, 2, (in.isRightclosed()) ? // 2 : 0, Color.black)); jp.setPreferredSize(new Dimension((int)((boundingInterval.getEnd() - boundingInterval.getStart())*PixelTime), PSIZE)); return jp; } /** Computes the value of this real for a given instant. * The instant is just given as a double. * If the moving real is not defined at the given instant null is returned. **/ public Double getValueAt(double time){ int index = IntervalSearch.getTimeIndex(time,Intervals); return getValueAt(time,index); } /** Computes the value for a given index * There is no check wether the given time is contained in * the interval determined by index. **/ private Double getValueAt(double time,int index){ // check for correct index if(index<0 || index >= Intervals.size()) return null; Interval CurrentInterval = (Interval) Intervals.get(index); MRealMap CurrentMap = (MRealMap) MRealMaps.get(index); // in this version, the interval is ignored, in the // new version implemented by Victor we have to subtract the // starting point of the interval from time first double start=CurrentInterval.getStart(); time -= start; double polyvalue = CurrentMap.a*time*time + CurrentMap.b*time + CurrentMap.c; if(!CurrentMap.f){ return new Double(polyvalue); }else{ if(polyvalue<0){ Reporter.writeError("Wrong MRealMap detected !!!"+ "attempt to compute the sqareroot of a negative number"); return null; }else{ return new Double(Math.sqrt(polyvalue)); } } } /** computes the minimum and the maximum value **/ private void computeMinMax(){ min = 0.0; max = 0.0; if(Intervals==null){ return; } boolean first = true; int size = Intervals.size(); for(int i=0;i=0){ // ensure a defined value y = map.f?Math.sqrt(c):c; if(first){ first=false; min=y; max=y; }else{ if(ymax){ max=y; } } } // check the end of the interval double t = end-start; double ty = a*t*t + b*t + c; if(!map.f || ty>=0){ y = map.f?Math.sqrt(ty):ty; if(first){ first=false; min=y; max=y; }else{ if(ymax){ max=y; } } } // check a possible angular point if(a!=0.0){ t = start - b / (2*a); // the moved angular point // check whether t is inside interval if(t>0 && t < (end-start)){ ty = a*t*t + b*t + c; if(!map.f || ty>=0){ y = map.f?Math.sqrt(ty):ty; if(first){ first=false; min=y; max=y; }else{ if(ymax){ max=y; } } } } } return !first; } /** Returns the interval of this moving real **/ public Interval getInterval(){ return boundingInterval; } /** * Scans the representation of a movingreal datatype * @param v A list of time-intervals with the parameter for a quadratic or squareroot formula * @see sj.lang.ListExpr * @see Source */ public void ScanValue (ListExpr v) { if(isUndefined(v)){ err=false; defined=false; return; } defined=true; if (v.isEmpty()){ err=false; // allow empty mreals return; } while (!v.isEmpty()) { ListExpr le = v.first(); Interval in=null; ListExpr map=null; int len = le.listLength(); if(len!=2 && len !=8){ Reporter.debug("invalid listlength, (2 or 8 expected but got " + len); return; } if (len == 8){ Reporter.writeWarning("Warning: deprecated list representation for moving real"); in = LEUtils.readInterval(ListExpr.fourElemList(le.first(), le.second(), le.third(), le.fourth())); map = le.rest().rest().rest().rest(); } if(len == 2){ in = LEUtils.readInterval(le.first()); map = le.second(); } MRealMap rm = readMRealMap(map); if ((in == null) || (rm == null)) { if(in==null){ Reporter.debug("Error in interval representation "); } if(rm==null){ Reporter.debug("error in map representation"); } return; } Intervals.add(in); MRealMaps.add(rm); v = v.rest(); } err = false; } /** * This method reads the parameter for a quadratic or squareroot formula into a MRealMap-instance * @param le A four element list * @return A MRealMap-instance with the formula parameter */ protected MRealMap readMRealMap (ListExpr le) { Double value[] = { null, null, null }; if (le.listLength() != 4) return null; for (int i = 0; i < 3; i++) { value[i] = LEUtils.readNumeric(le.first()); if (value[i] == null) return null; le = le.rest(); } if (le.first().atomType() != ListExpr.BOOL_ATOM) return null; return new MRealMap(value[0].doubleValue(), value[1].doubleValue(), value[2].doubleValue(), le.first().boolValue()); } public void init (String name, int nameWidth,int indent, ListExpr type, ListExpr value, QueryResult qr) { AttrName = extendString(name,nameWidth, indent); err=true; ScanValue(value); computeMinMax(); if (err) { defined = false; Reporter.writeError("Error in ListExpr :parsing aborted"); qr.addEntry(new String(AttrName + ": TA(MReal)")); return; } else qr.addEntry(this); // compute the bounding box of all intervals boundingInterval = null; for (int i = 0; i < Intervals.size(); i++) { Interval in = (Interval)Intervals.elementAt(i); if(!in.isInfinite()){ if (boundingInterval == null) { boundingInterval = in.copy(); } else { boundingInterval.unionInternal(in); } } } } /** The text representation of this object * @see Source */ public String toString () { return AttrName + " : TA(MReal) "; } /** A method of the Timed-Interface * @return The Vector representation of the time intervals this instance is defined at * @see Source */ public Vector getIntervals(){ return Intervals; } /* Implementation of LabelAttribute */ public String getLabel(double time){ if(!defined){ return "undefined"; } Double d = getValueAt(time); if(d==null){ return "undefined"; } return format.format(d.doubleValue()); } /* Implementation of the RenderAttribute interface **/ public boolean mayBeDefined(){ return defined; } public double getMinRenderValue(){ return min; } public double getMaxRenderValue(){ return max; } public boolean isDefined(double time){ if(!defined){ return false; } Double d = getValueAt(time); return d!=null; } public double getRenderValue(double time){ Double d = getValueAt(time); if(d==null){ return (max+min)/2; } else{ return d.doubleValue(); } } /** The class which holds the formula parameter for an interval */ class MRealMap { double a, b, c; boolean f; /** * Constructor * @param double x1 Quadratic koefficient * @param double x2 Linear koefficient * @param double x3 Constant koefficient * @param boolean y True if Squareroot */ public MRealMap (double x1, double x2, double x3, boolean y) { a = x1; b = x2; c = x3; f = y; } /** * * @return Textrepresentation of a MRealMap */ public String toString () { if (!f) return a + "t^2+" + b + "t+" + c; else return "SQRT(" + a + "t^2+" + b + "t+" + c + ")"; } } /** Special class to draw the MRealMap function */ class MRealLabel extends JLabel { int ValueIndex; /** * constructor * @param String s Label of this function */ public MRealLabel (String s) { super(s); } /** * Paints the function * @param Graphics g The context to draw in */ public void paintComponent(Graphics g){ super.paintComponent(g); g.setColor(Color.black); Interval in = (Interval)Intervals.elementAt(ValueIndex); MRealMap mr = (MRealMap)MRealMaps.elementAt(ValueIndex); int start = (int)((in.getStart() - boundingInterval.getStart())*PixelTime); int end = (int)((in.getEnd() - boundingInterval.getStart())*PixelTime); double y1=-PSIZE/(max-min); double y2=PSIZE*max/(max-min); int xpos=0; int lastx=0,lasty=0; for (int x=start;x<=end;x++) { double actTime = (double)x/PixelTime+boundingInterval.getStart(); Double Mv = getValueAt(actTime,ValueIndex); if(Mv==null){ Reporter.writeError("Error in computing the real value for instant "+actTime); }else{ double mv=Mv.doubleValue(); int ypos=(int)(mv*y1+y2); if(x==start){ // ensure to draw also a single point g.drawLine(xpos,ypos,xpos,ypos+1); } else{ g.drawLine(lastx,lasty,xpos,ypos); } lastx = xpos; lasty = ypos; } xpos++; } } /** * You can point with the mouse to get the value at a time * @param evt MouseEvent * @return Function value as string */ public String getToolTipText (MouseEvent evt) { Interval in = (Interval)Intervals.elementAt(ValueIndex); double actTime = in.getStart() + evt.getX()/PixelTime; Double Mv = getValueAt(actTime,ValueIndex); if(Mv!=null){ double mv=Mv.doubleValue(); return LEUtils.convertTimeToString(actTime) + "=" + mv; } else{ return "Error in computing value at instant "+LEUtils.convertTimeToString(actTime); } } } //private static MultiFunctionFrame functionframe = new MultiFunctionFrame(); private static FunctionFrame functionframe = new FunctionFrame(); }