/* ========================
* JSynoptic : a free Synoptic editor
* ========================
*
* Project Info: http://jsynoptic.sourceforge.net/index.html
*
* This program is free software; you can redistribute it and/or modify it under the terms
* of the GNU Lesser General Public License as published by the Free Software Foundation;
* either version 2.1 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 Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public License along with this
* program; if not, write to the Free Software Foundation, Inc., 59 Temple Place, Suite 330,
* Boston, MA 02111-1307, USA.
*
* (C) Copyright 2001-2003, by :
* Corporate:
* Astrium SAS
* EADS CRC
* Individual:
* Nicolas Brodu
*
* $Id: EllipseShape.java,v 1.23 2008/09/05 12:23:22 ogor Exp $
*
* Changes
* -------
* 21-Oct-2003 : Initial version (NB);
*
*/
package jsynoptic.builtin;
import java.awt.Shape;
import java.awt.geom.Arc2D;
import java.awt.geom.Ellipse2D;
import java.awt.geom.RectangularShape;
import java.util.Arrays;
import java.util.List;
import java.util.ResourceBundle;
import jsynoptic.builtin.ui.EllipsePropertiesPanel;
import simtools.data.DataException;
import simtools.data.DataSource;
import simtools.data.DataSourcePool;
import simtools.data.UnsupportedOperation;
import simtools.shapes.AbstractShape;
import simtools.ui.JPropertiesPanel;
import simtools.ui.ResourceFinder;
/**
* The Ellipse shape handles ellipses (inc. circles) and arcs
* It delegates internally to a corresponding java shape
*/
public class EllipseShape extends Abstract2DShape {
static final long serialVersionUID = 6256410262456113545L;
public static ResourceBundle resources = ResourceFinder.get(EllipseShape.class);
public static final int ANGLE_UNIT_DEGREE = 0;
public static final int ANGLE_UNIT_RADIAN = 1;
public static final int TYPE_FULL = 0;
public static final int TYPE_PIE = 1;
public static final int TYPE_CHORD = 2;
public static final int TYPE_OPEN = 3;
protected int startUnit, endUnit;
protected transient double start;
protected transient double end;
protected transient Shape ellipse;
protected transient DataSource startAngleSource, endAngleSource;
protected transient long startAngleSourceIndex, endAngleSourceIndex;
protected transient boolean dirtyArc = false;
/**
* @param ox
* @param oy
* @param width
* @param height
*/
public EllipseShape(int ox, int oy, int width, int height) {
super(ox, oy, width, height);
allowResize = true;
fixedRatio = false;
ellipse = new Ellipse2D.Double(ox, oy-_h, width-1, height-1);
start = 0d;
end = 0d;
}
/* (non-Javadoc)
* @see jsynoptic.builtin.SimpleShape#getDelegateShape()
*/
protected Shape getDelegateShape() {
return ellipse;
}
/* (non-Javadoc)
* @see simtools.shapes.AbstractShape#translate(int, int)
*/
public void translate(int dx, int dy) {
super.translate(dx, dy);
if (ellipse instanceof Ellipse2D.Double) {
Ellipse2D.Double e = (Ellipse2D.Double)ellipse;
e.x+=dx; e.y+=dy;
return;
}
if (ellipse instanceof Arc2D.Double) {
Arc2D.Double e = (Arc2D.Double)ellipse;
e.x+=dx; e.y+=dy;
return;
}
}
/* (non-Javadoc)
* @see simtools.shapes.AbstractShape#setAnchor(int, int)
*/
public void setAnchor(int ox, int oy) {
super.setAnchor(ox, oy);
if (ellipse instanceof Ellipse2D.Double) {
Ellipse2D.Double e = (Ellipse2D.Double)ellipse;
e.x=ox; e.y=oy-_h;
return;
}
if (ellipse instanceof Arc2D.Double) {
Arc2D.Double e = (Arc2D.Double)ellipse;
e.x=ox; e.y=oy-_h;
return;
}
}
/* (non-Javadoc)
* @see simtools.diagram.Resizable#resize(int, int)
*/
public void resize(int dx, int dy) {
super.resize(dx, dy);
if (ellipse instanceof Ellipse2D.Double) {
Ellipse2D.Double e = (Ellipse2D.Double)ellipse;
e.x=_ox; e.y=_oy-_h;
e.height=_h-1; e.width=_w-1;
}
if (ellipse instanceof Arc2D.Double) {
Arc2D.Double e = (Arc2D.Double)ellipse;
e.x=_ox; e.y=_oy-_h;
e.height=_h-1; e.width=_w-1;
}
}
/* (non-Javadoc)
* @see jsynoptic.builtin.Abstract2DShape#getPanel(java.util.List)
*/
public JPropertiesPanel getPanel(List properties) {
if (properties == null){
return null;
}
if (properties.containsAll(Arrays.asList(new EllipseShapePropertiesNames().getPropertyNames()))){
return new EllipsePropertiesPanel(Builtin.resources.getString("Ellipse"));
} else {
return super.getPanel(properties);
}
}
/* (non-Javadoc)
* @see simtools.shapes.AbstractShape#getShapeName()
*/
public String getShapeName(){
return Builtin.resources.getString("Ellipse");
}
// return true if the arc was modified, false otherwise => repaint only when necessary
protected boolean updateArc() {
if (!(ellipse instanceof Arc2D.Double)) return false;
Arc2D.Double a = (Arc2D.Double)ellipse;
double s, e;
if(startAngleSource!=null){
try {
s = startAngleSource.getDoubleValue(startAngleSourceIndex);
if (startUnit == ANGLE_UNIT_RADIAN) s = Math.toDegrees(s);
} catch (DataException de) {
s = a.start;
}
}else{
s=a.start;
}
if(endAngleSource!=null){
try {
e = endAngleSource.getDoubleValue(endAngleSourceIndex);
if (endUnit == ANGLE_UNIT_RADIAN) e = Math.toDegrees(e);
} catch (DataException de) {
e = a.start + a.extent;
}
}
else{
e = a.start + a.extent;
}
start=s;
if (startUnit == ANGLE_UNIT_RADIAN) start = Math.toRadians(s);
end=e;
if (endUnit == ANGLE_UNIT_RADIAN) end = Math.toRadians(e);
if ((a.start == s) && (e == a.start + a.extent)) return false;
ellipse = new Arc2D.Double(_ox, _oy-_h, _w-1, _h-1, s, e - s, a.getArcType());
return true;
}
/* (non-Javadoc)
* @see simtools.data.EndNotificationListener#notificationEnd(java.lang.Object)
*/
public void notificationEnd(Object referer) {
if (dirtyArc) {
dirty |= updateArc();
dirtyArc = false;
}
// parent for colors & update
super.notificationEnd(referer);
}
/* (non-Javadoc)
* @see simtools.data.DataSourceListener#DataSourceIndexRangeChanged(simtools.data.DataSource, long, long)
*/
public void DataSourceValueChanged(DataSource ds, long minIndex, long maxIndex) {
if (ds.equals(startAngleSource)) {
if ((startAngleSourceIndex >= minIndex) && (startAngleSourceIndex <= maxIndex)) dirtyArc = true;
}
if (ds.equals(endAngleSource)) {
if ((endAngleSourceIndex >= minIndex) && (endAngleSourceIndex <= maxIndex)) dirtyArc = true;
}
super.DataSourceValueChanged(ds, minIndex, maxIndex);
}
/* (non-Javadoc)
* @see simtools.data.DataSourceListener#DataSourceValueChanged(simtools.data.DataSource, long, long)
*/
public void DataSourceIndexRangeChanged(DataSource ds, long startIndex, long lastIndex) {
if (ds.equals(startAngleSource)) {
startAngleSourceIndex = lastIndex;
dirtyArc = true;
}
if (ds.equals(endAngleSource)) {
endAngleSourceIndex = lastIndex;
dirtyArc = true;
}
super.DataSourceIndexRangeChanged(ds, startIndex, lastIndex);
}
/* (non-Javadoc)
* @see simtools.data.DataSourceListener#DataSourceReplaced(simtools.data.DataSource, simtools.data.DataSource)
*/
public void DataSourceReplaced(DataSource oldData, DataSource newData) {
if(oldData==startAngleSource){
startAngleSource=newData;
if (startAngleSource!=null) {
startAngleSource.addListener(this);
startAngleSource.addEndNotificationListener(this);
try {
startAngleSourceIndex = startAngleSource.getLastIndex();
} catch (UnsupportedOperation uo1) {
startAngleSourceIndex = 0;
}
}
oldData.removeListener(this);
oldData.removeEndNotificationListener(this);
dirtyArc = true;
}
if(oldData==endAngleSource){
endAngleSource=newData;
if (endAngleSource!=null) {
endAngleSource.addListener(this);
endAngleSource.addEndNotificationListener(this);
try {
endAngleSourceIndex = endAngleSource.getLastIndex();
} catch (UnsupportedOperation uo1) {
endAngleSourceIndex = 0;
}
}
oldData.removeListener(this);
oldData.removeEndNotificationListener(this);
dirtyArc = true;
}
super.DataSourceReplaced(oldData,newData);
}
/* (non-Javadoc)
* @see simtools.shapes.AbstractShape#subscribeToDataNotifications()
*/
public void processShapeRestoring(){
if (startAngleSource!=null) {
startAngleSource.addListener(this);
startAngleSource.addEndNotificationListener(this);
try {
startAngleSourceIndex = startAngleSource.getLastIndex();
} catch (UnsupportedOperation uo1) {
startAngleSourceIndex = 0;
}
}
if (endAngleSource!=null) {
endAngleSource.addListener(this);
endAngleSource.addEndNotificationListener(this);
try {
endAngleSourceIndex = endAngleSource.getLastIndex();
} catch (UnsupportedOperation uo1) {
endAngleSourceIndex = 0;
}
}
super.processShapeRestoring();
}
/* (non-Javadoc)
* @see simtools.shapes.AbstractShape#unsubscribeToDataNotifications()
*/
public void processShapeRemoving(){
if (endAngleSource != null) {
endAngleSource.removeListener(this);
endAngleSource.removeEndNotificationListener(this);
}
if (startAngleSource != null) {
startAngleSource.removeListener(this);
startAngleSource.removeEndNotificationListener(this);
}
super.processShapeRemoving();
}
// Take care of serialisation. Special handling for datasources
private void writeObject(java.io.ObjectOutputStream out) throws java.io.IOException {
out.defaultWriteObject();
// Ellipse2D and Arc2D not serializable
// In addition, we don't need to store the width, height, position, as they are the same as this object
// => store type, and reconstruct on read
// type=0 => Ellipse2D, type=1 => arc2D
if (ellipse instanceof Ellipse2D.Double)
out.writeInt(0);
else if (ellipse instanceof Arc2D.Double) {
Arc2D.Double a = (Arc2D.Double)ellipse;
out.writeInt(1);
out.writeDouble(a.start);
out.writeDouble(a.extent);
out.writeInt(a.getArcType());
}
DataSourcePool.global.writeDataSource(out, startAngleSource);
DataSourcePool.global.writeDataSource(out, endAngleSource);
}
private void readObject(java.io.ObjectInputStream in) throws java.lang.ClassNotFoundException, java.io.IOException {
in.defaultReadObject();
switch(in.readInt()) {
case 0:
ellipse = new Ellipse2D.Double(_ox, _oy-_h, _w-1, _h-1);
break;
case 1:
double s = in.readDouble();
double ex= in.readDouble();
int type = in.readInt();
ellipse = new Arc2D.Double(_ox, _oy-_h, _w-1, _h-1, s, ex, type);
start=s;
if (startUnit == ANGLE_UNIT_RADIAN)
start = Math.toRadians(s);
end=s+ex;
if (endUnit == ANGLE_UNIT_RADIAN)
end = Math.toRadians(s+ex);
break;
}
startAngleSource = DataSourcePool.global.readDataSource(in);
if (startAngleSource!=null) try {
startAngleSource.addListener(this);
startAngleSource.addEndNotificationListener(this);
startAngleSourceIndex = startAngleSource.getLastIndex();
}
catch (UnsupportedOperation uo1) {
startAngleSourceIndex = 0;
}
endAngleSource = DataSourcePool.global.readDataSource(in);
if (endAngleSource!=null) try {
endAngleSource.addListener(this);
endAngleSource.addEndNotificationListener(this);
endAngleSourceIndex = endAngleSource.getLastIndex();
}
catch (UnsupportedOperation uo1) {
endAngleSourceIndex = 0;
}
}
/* (non-Javadoc)
* @see simtools.shapes.AbstractShape#cloneShape()
*/
protected AbstractShape cloneShape() {
EllipseShape es = (EllipseShape)super.cloneShape();
es.ellipse = (Shape)((RectangularShape)ellipse).clone();
if(es.startAngleSource!=null){
es.startAngleSource.addEndNotificationListener(es);
es.startAngleSource.addListener(es);
}
if(es.endAngleSource!=null){
es.endAngleSource.addEndNotificationListener(es);
es.endAngleSource.addListener(es);
}
return es;
}
public void setPropertyValue(String name, Object value) {
super.setPropertyValue(name, value);
if(name.equalsIgnoreCase("ELLIPSE_TYPE")) {
if (value instanceof Integer) {
int ellipse_type = ((Integer)value).intValue();
if(ellipse_type == TYPE_FULL) {
ellipse = new Ellipse2D.Double(_ox, _oy - _h, _w - 1,
_h - 1);
if (startAngleSource != null)
startAngleSource.removeListener(this);
startAngleSource = null;
if (endAngleSource != null)
endAngleSource.removeListener(this);
endAngleSource = null;
} else {
double s=start;
if (startUnit == ANGLE_UNIT_RADIAN)
s = Math.toDegrees(start);
double e=end;
if (endUnit == ANGLE_UNIT_RADIAN)
e = Math.toDegrees(end);
switch (ellipse_type) {
case EllipseShape.TYPE_PIE:
ellipse = new Arc2D.Double(_ox, _oy-_h, _w-1, _h-1, s, e - s, Arc2D.PIE);
break;
case EllipseShape.TYPE_CHORD:
ellipse = new Arc2D.Double(_ox, _oy-_h, _w-1, _h-1, s, e - s, Arc2D.CHORD);
break;
case EllipseShape.TYPE_OPEN:
ellipse = new Arc2D.Double(_ox, _oy-_h, _w-1, _h-1, s, e - s, Arc2D.OPEN);
break;
}
}
}
} else if(name.equalsIgnoreCase("START_UNIT")) {
if(value instanceof Integer) {
startUnit = ((Integer)value).intValue();
}
} else if(name.equalsIgnoreCase("END_UNIT")) {
if(value instanceof Integer) {
endUnit = ((Integer)value).intValue();
}
} else if(name.equalsIgnoreCase("START_ANGLE")) {
if(value instanceof Double) {
start = ((Double)value).doubleValue();
}
} else if(name.equalsIgnoreCase("END_ANGLE")) {
if(value instanceof Double) {
end = ((Double)value).doubleValue();
}
} else if(name.equalsIgnoreCase("START_ANGLE_SOURCE")) {
if (startAngleSource!=null) {
startAngleSource.removeListener(this);
startAngleSource.removeEndNotificationListener(this);
startAngleSource=null;
}
if (value instanceof DataSource) {
startAngleSource = (DataSource) value;
try {
startAngleSourceIndex = startAngleSource.getLastIndex();
} catch (UnsupportedOperation e) {
startAngleSourceIndex = 0;
}
try {
start = startAngleSource.getDoubleValue(startAngleSourceIndex);
} catch (DataException e) {
}
startAngleSource.addListener(EllipseShape.this);
startAngleSource.addEndNotificationListener(EllipseShape.this);
}
} else if (name.equalsIgnoreCase("END_ANGLE_SOURCE")) {
if (endAngleSource!=null) {
endAngleSource.removeListener(this);
endAngleSource.removeEndNotificationListener(this);
endAngleSource=null;
}
if (value instanceof DataSource) {
endAngleSource = (DataSource) value;
try {
endAngleSourceIndex = endAngleSource.getLastIndex();
} catch (UnsupportedOperation e) {
endAngleSourceIndex = 0;
}
try {
end = endAngleSource.getDoubleValue(endAngleSourceIndex);
} catch (DataException e) {
}
endAngleSource.addListener(EllipseShape.this);
endAngleSource.addEndNotificationListener(EllipseShape.this);
}
}
}
public String[] getPropertyNames(){
if (_propertyNames==null)
_propertyNames = new EllipseShapePropertiesNames().getPropertyNames();
return _propertyNames;
}
public Object getPropertyValue(String name) {
Object res = super.getPropertyValue(name);
if(name.equalsIgnoreCase("ELLIPSE_TYPE")) {
if(ellipse instanceof Ellipse2D.Double) {
res=new Integer(EllipseShape.TYPE_FULL);
} else {
Arc2D.Double arc = (Arc2D.Double)ellipse;
switch(arc.getArcType()) {
case Arc2D.PIE:
res=new Integer(EllipseShape.TYPE_PIE);
break;
case Arc2D.CHORD:
res=new Integer(EllipseShape.TYPE_CHORD);
break;
case Arc2D.OPEN:
res=new Integer(EllipseShape.TYPE_OPEN);
break;
}
}
} else if(name.equalsIgnoreCase("START_UNIT")) {
res = new Integer(startUnit);
} else if(name.equalsIgnoreCase("END_UNIT")) {
res = new Integer(endUnit);
} else if(name.equalsIgnoreCase("START_ANGLE")) {
try {
Arc2D.Double arc = (Arc2D.Double)ellipse;
start = arc.start;
if (startUnit == ANGLE_UNIT_RADIAN)
start = Math.toRadians(start);
res = new Double(start);
} catch (ClassCastException e) {
res = null;
}
} else if(name.equalsIgnoreCase("END_ANGLE")) {
try {
Arc2D.Double arc = (Arc2D.Double)ellipse;
end = arc.start + arc.extent;
if (endUnit == ANGLE_UNIT_RADIAN)
end = Math.toRadians(end);
res = new Double(end);
} catch (ClassCastException e) {
res = null;
}
} else if(name.equalsIgnoreCase("START_ANGLE_SOURCE")) {
res = startAngleSource;
} else if(name.equalsIgnoreCase("END_ANGLE_SOURCE")) {
res = endAngleSource;
}
return res;
}
public static class EllipseShapePropertiesNames extends Abstract2DShapePropertiesNames{
private static transient String[] props = new String[] { "START_UNIT", "START_ANGLE", "START_ANGLE_SOURCE",
"END_UNIT", "END_ANGLE","END_ANGLE_SOURCE","ELLIPSE_TYPE" };
public EllipseShapePropertiesNames(){
super();
for (int i=0;i<props.length;i++){
propertyNames.add(props[i]);
}
}
}
}