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

563 lines
16 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 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<size;i++){
Interval interval = (Interval) Intervals.get(i);
MRealMap map = (MRealMap) MRealMaps.get(i);
if(updateMinMax(interval,map,first)){
first = false;
}
}
}
/** computes the extremums of the given interval-map combination
* and updates minvalue and maxvalue if required.
* @param interval the interval to check
* @param map the map hlding for this interval
* @param first flag indicating that min and max are undefined up to now
* @return true if the values are defined after calling this functiom
**/
private boolean updateMinMax(Interval interval, MRealMap map, boolean first){
double a = map.a;
double b = map.b;
double c = map.c;
double start = interval.getStart();
double end = interval.getEnd();
// check the intervals start
double y;
if(!map.f || c>=0){ // ensure a defined value
y = map.f?Math.sqrt(c):c;
if(first){
first=false;
min=y;
max=y;
}else{
if(y<min){
min=y;
}
if(y>max){
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(y<min){
min=y;
}
if(y>max){
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(y<min){
min=y;
}
if(y>max){
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 <a href="Dsplmovingrealsrc.html#ScanValue">Source</a>
*/
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 <a href="Dsplmovingrealsrc.html#toString">Source</a>
*/
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 <a href="Dsplmovingrealsrc.html#getIntervals">Source</a>
*/
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();
}