/*
* Copyright (C) 2011 Alasdair C. Hamilton
*
* This program 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 3 of the License, or
* (at your option) any later version.
*
* This program 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 this program. If not, see <http://www.gnu.org/licenses/>
*/
package ketUI.panel;
import geom.Offset;
import java.util.*;
import java.awt.Stroke;
import java.awt.BasicStroke;
import java.awt.Graphics;
import java.awt.Graphics2D;
import java.awt.Color;
import geom.Position;
import ket.*;
import ket.display.*;
import ket.display.box.Box;
import ket.display.box.BoxFactory;
import ket.display.box.BoxText;
import ket.display.box.BoxTools;
import ket.math.*;
import ketUI.Document;
/**
* Represent the current equation as a graph.
*/
class Node extends Label {
final Argument argument;
int indices;
Color colour;
int depth;
int index;
double range;
double direction; // rad
boolean leaf;
Node parent;
int parentSize;
boolean highlight;
boolean visible;
public Node(Argument argument, Node parent, ColourScheme colourScheme, double edgeLength) {
this.argument = argument;
Purpose purpose = argument.getPurpose();
this.name = purpose!=null ? purpose.getName() : "?";
this.colour = colourScheme.getBoxColour(argument); // used?
if (colourScheme instanceof ColourSchemeDecorator) {
this.highlight = ((ColourSchemeDecorator) colourScheme).isSelected(argument);
} else {
this.highlight = false;
}
this.parent = parent;
depth = argument.getDepth();
this.visible = argument.isVisible();
if (parent==null) {
index = 0;
direction = -Math.PI/2.0;
range = 5.0 * Math.PI / 6.0; // i.e. 180 deg - 15 degrees on either side.
x = 0.0;
y = 0.0;
leaf = argument.isLeaf();
} else {
index = argument.getIndex();
parentSize = calcParentBranchSize(argument);
range = parent.range / parentSize;
double frac = (2.0*index + 1.0) / (2.0 * parentSize);
direction = parent.direction + parent.range*(frac-0.5);
x = parent.x + edgeLength*Math.cos(-direction);
y = parent.y + edgeLength*Math.sin(-direction);
leaf = argument.size()==0;
}
}
public Integer getEquationIndex() {
return argument.getEquationIndex();
}
public boolean family(Node node) {
return this.parent==node || (node!=null && this==node.parent);
}
/*
* Square restoring force from spring equilibrium length.
*/
public Offset tension(double edgeLength) {
if (parent==null) {
return new Offset(0.0, 0.0);
}
double dx = parent.x - this.x;
double dy = parent.y - this.y;
double length = Math.sqrt(dx*dx + dy*dy);
double error = length - edgeLength;
error = 1.0E-2 * error * Math.abs(error);
return new Offset(error*dx/length, error*dy/length); // error * r_unit
}
private int calcParentBranchSize(Argument a) {
Branch parentBranch = a.getParentBranch();
return parentBranch!=null ? parentBranch.size() : 1;
}
public String toString() {
return String.format("depth=%d; range=%g; x,y=%g,%g; direction=%g, %s, parentSize=%d\n",
depth, 180.0*range/Math.PI, x, y, 180.0*direction/Math.PI, leaf?"<leaf>":"", parentSize);
}
@Override
public boolean isSimpleFunction() {
if (argument==null) return false;
Function f = argument.getFunction();
if (f==Function.ADD) return true;
if (f==Function.MINUS) return true;
if (f==Function.TIMES) return true;
if (f==Function.FRACTION) return true;
if (f==Function.POWER) return true;
if (f==Function.EQUALS) return true;
return false;
}
}