/*
* Copyright (c) 2014. Matthew Campbell <matthew.campbell@mq.edu.au>, David R. Damerell <david@nixbioinf.org>.
*
* This file is part of GlycanBuilder Vaadin Release and its affliated projects EUROCarbDB, UniCarb-DB and UniCarbKB.
*
* This program is free software 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.
*
* GlycanBuilder Vaadin Release 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 (LICENSE.txt) for more details.
*
* You should have received a copy of the GNU General Public License
* along with GlycanBuilder Vaadin Release. If not, see <http ://www.gnu.org/licenses/>.
*/
package ac.uk.icl.dell.vaadin.canvas.shapes;
import java.awt.Color;
import java.awt.Rectangle;
import org.eurocarbdb.application.glycanbuilder.ResidueStyle;
import ac.uk.icl.dell.vaadin.canvas.basiccanvas.BasicCanvas;
import ac.uk.icl.dell.vaadin.canvas.hezamu.canvas.Canvas;
public abstract class BaseShape {
double x,y,w,h;
ResidueStyle style;
Canvas canvas;
boolean selected;
public BaseShape(double x, double y, double w, double h, ResidueStyle style,Canvas canvas,boolean selected){
this.x=x; this.y=y; this.w=w; this.h=h; this.style=style; this.canvas=canvas; this.selected=selected;
}
public void paint(){
canvas.saveContext();
if(selected){
canvas.setLineWidth(2);
}else{
canvas.setLineWidth(1);
}
setShapeFillStyle();
paintShape();
if(selected){
canvas.setGlobalAlpha(0.6);
}
setInternalShapeFillStyle();
paintFillShape();
//if(selected){
// paintSelected();
//}
canvas.restoreContext();
}
protected void paintSelected(){
canvas.saveContext();
canvas.setGlobalAlpha(0.4);
canvas.fillRect(x, y, w, h);
setStrokeColour(style.getShapeColor());
canvas.strokeRect(x, y, w, h);
canvas.restoreContext();
}
protected void internalShapeFull(){
throw new UnsupportedOperationException();
}
protected void internalShapeLeft(){
throw new UnsupportedOperationException();
}
protected void internalShapeRight(){
throw new UnsupportedOperationException();
}
protected void internalShapeTop(){
throw new UnsupportedOperationException();
}
protected void internalShapeBottom(){
throw new UnsupportedOperationException();
}
protected void internalShapeTopLeft(){
throw new UnsupportedOperationException();
}
protected void internalShapeTopRight(){
throw new UnsupportedOperationException();
}
protected void internalShapeBottomRight(){
throw new UnsupportedOperationException();
}
protected void internalShapeBottomLeft(){
throw new UnsupportedOperationException();
}
protected void paintFillShape(){
String fillstyle = style.getFillStyle();
if(fillstyle.equals("empty")){
return;
}
if(fillstyle.equals("full")){
internalShapeFull();
}else if(fillstyle.equals("left")){
internalShapeLeft();
}else if(fillstyle.equals("top")){
internalShapeTop();
}else if(fillstyle.equals("right")){
internalShapeRight();
}else if(fillstyle.equals("bottom")){
internalShapeBottom();
}else if(fillstyle.equals("topleft")){
internalShapeTopLeft();
}else if(fillstyle.equals("topright")){
internalShapeTopRight();
}else if(fillstyle.equals("bottomright")){
internalShapeBottomRight();
}else if(fillstyle.equals("bottomleft")){
internalShapeBottomLeft();
}else if(fillstyle.equals("circle")){
canvas.beginPath();
canvas.arc(x+w/2., y+h/2., w/8.,0*Math.PI,Math.PI*2,false);
canvas.closePath();
canvas.fill();
setFillStyle(style.getShapeColor());
canvas.stroke();
}else if(fillstyle.equals("checkered")){
canvas.setLineWidth(0.5);
canvas.beginPath();
canvas.moveTo(x+w/2., y);
canvas.lineTo(x+w/2., y+h);
canvas.moveTo(x, y+h/2.);
canvas.lineTo(x+w, y+h/2.);
canvas.closePath();
setFillStyle(style.getShapeColor());
canvas.stroke();
}
//else{
// double cx = x+w/2.;
// double cy = y+h/2.;
// double rx = w/6.;
// double ry = h/6.;
// if( fillstyle.equals("circle") ){
// canvas.beginPath();
// canvas.arc(x+w/2., y+h/2., w/2.,0*Math.PI,Math.PI*2,false);
// canvas.closePath();
// canvas.fill();
// setFillStyle(style.getShapeColor());
// canvas.stroke();
// }
// }
// if( fillstyle.equals("left") )
// return new Rectangle2D.Double(x,y,w/2.,h);
// if( fillstyle.equals("top") )
// return new Rectangle2D.Double(x,y,w,h/2.);
// if( fillstyle.equals("right") )
// return new Rectangle2D.Double(x+w/2.,y,w/2.,h);
// if( fillstyle.equals("bottom") )
// return new Rectangle2D.Double(x,y+h/2.,w,h/2.);
// if( fillstyle.equals("topleft") )
// return createTriangle(x,y,x+w,y,x,y+h);
// if( fillstyle.equals("topright") )
// return createTriangle(x,y,x+w,y,x+w,y+h);
// if( fillstyle.equals("bottomright") )
// return createTriangle(x+w,y,x+w,y+h,x,y+h);
// if( fillstyle.equals("bottomleft") )
// return createTriangle(x,y,x+w,y+h,x,y+h);
//
// double cx = x+w/2.;
// double cy = y+h/2.;
// double rx = w/6.;
// double ry = h/6.;
// if( fillstyle.equals("circle") )
// return new Ellipse2D.Double(cx-rx,cy-ry,2.*rx,2.*ry);
// if( fillstyle.equals("checkered") )
// return createCheckered(x,y,w,h);
// if( fillstyle.startsWith("arc") ) {
// Vector<String> tokens = TextUtils.tokenize(fillstyle,"_");
// int first_pos = Integer.parseInt(tokens.elementAt(1));
// int last_pos = Integer.parseInt(tokens.elementAt(2));
// return createArc(x,y,w,h,first_pos,last_pos);
// }
//
//
// return null;
}
protected abstract void paintShape();
final protected void setFillStyle(Color colour){
canvas.setFillStyle(colour.getRed(),colour.getGreen(), colour.getBlue());
}
final protected void setStrokeColour(Color colour){
canvas.setStrokeStyle(colour.getRed(),colour.getGreen(), colour.getBlue());
}
final protected void setShapeFillStyle(){
setFillStyle(style.isFillNegative() ? style.getFillColor() : Color.WHITE);
}
final protected void setInternalShapeFillStyle(){
setFillStyle(style.isFillNegative() ? Color.WHITE : style.getFillColor());
}
final static protected void createTriangle(double x1,double y1, double x2, double y2, double x3, double y3,Canvas canvas){
canvas.beginPath();
canvas.moveTo(x1, y1);
canvas.lineTo(x2, y2);
canvas.lineTo(x3, y3);
canvas.closePath();
}
final static protected void createTriangle(double angle, double x, double y, double w, double h,Canvas canvas){
double x1,y1,x2,y2,x3,y3;
if(angle>=-Math.PI/4. && angle<=Math.PI/4.){
//pointing right
x1=(x+w);
y1=(y+h/2);
x2=x;
y2=(y+h);
x3=x;
y3=y;
}else if(angle>=Math.PI/4. && angle<=3.*Math.PI/4.){
//pointing down
x1=x+w/2;
y1=y+h;
x2=x;
y2=y;
x3=x+w;
y3=y;
}else if(angle>=-3.*Math.PI/4. && angle<=-Math.PI/4. ){
//pointing up
x1=x+w/2;
y1=y;
x2=x+w;
y2=y+h;
x3=x;
y3=y+h;
}else{
//pointing left
x1=x;
y1=y+h/2;
x2=x+w;
y2=y+h;
x3=x+w;
y3=y;
}
createTriangle(x1, y1, x2, y2, x3, y3, canvas);
}
final static public void createTriangle(double x,double y,double w,double h,Canvas canvas){
createTriangle(-3.*Math.PI/4, x, y, w, h, canvas);
}
final static public void createDiamond(double x,double y,double w,double h,Canvas canvas){
createDiamond(x, y, w, h, canvas, true);
}
final static public void createDiamond(double x,double y,double w,double h,Canvas canvas,boolean setPath){
if((w%2)==1){
w++;
}
if((h%2)==1){
h++;
}
if(setPath){
canvas.beginPath();
}
canvas.moveTo(x+w/2, y);
canvas.lineTo(x+w, y+h/2);
canvas.lineTo(x+w/2, y+h);
canvas.lineTo(x, y+h/2);
if(setPath){
canvas.closePath();
}
}
final static public void createHexagon(double x,double y,double w,double h,Canvas canvas){
double rx = w/2.;
double ry = h/2.;
double cx = x+w/2.;
double cy = y+h/2.;
double step = Math.PI/3.;
canvas.beginPath();
canvas.moveTo(cx+rx*Math.cos(0*step),cy+ry*Math.sin(0*step));
for(int i=1; i<=6; i++ ) {
canvas.lineTo(cx+rx*Math.cos(i*step),cy+ry*Math.sin(i*step));
}
canvas.closePath();
}
final static void createHeptagon(double x,double y,double w,double h,Canvas canvas){
//createTriangle(x, y, w, h, canvas);
double rx = w/2.;
double ry = h/2.;
double cx = x+w/2.;
double cy = y+h/2.;
double step = Math.PI/3.5;
canvas.beginPath();
canvas.moveTo(cx+rx*Math.cos(0*step-Math.PI/2.),cy+ry*Math.sin(0*step-Math.PI/2.));
for(int i=1; i<=7; i++ ) {
canvas.lineTo(cx+rx*Math.cos(i*step-Math.PI/2.),cy+ry*Math.sin(i*step-Math.PI/2.));
}
canvas.closePath();
}
final static void createStar(double x,double y,double w,double h,Canvas canvas, int points){
double rx = w/2.;
double ry = h/2.;
double cx = x+w/2.;
double cy = y+h/2.;
double step = Math.PI/(double)points;
double nstep = Math.PI/2.-2.*step;
double mrx = rx/(Math.cos(step)+Math.sin(step)/Math.tan(nstep));
double mry = ry/(Math.cos(step)+Math.sin(step)/Math.tan(nstep));
canvas.beginPath();
canvas.moveTo(cx+rx*Math.cos(0*step-Math.PI/2.), cy+ry*Math.sin(0*step-Math.PI/2.));
for(int i=1; i<=2*points; i++ ) {
if((i%2)==0){
canvas.lineTo(cx+rx*Math.cos(i*step-Math.PI/2.), cy+ry*Math.sin(i*step-Math.PI/2.));
}else{
canvas.lineTo(cx+mrx*Math.cos(i*step-Math.PI/2.), cy+mry*Math.sin(i*step-Math.PI/2.));
}
}
canvas.closePath();
}
final static public void createPentagon(double x,double y,double w,double h,Canvas canvas){
double rx = w/2.;
double ry = h/2.;
double cx = x+w/2.;
double cy = y+h/2.;
double step = Math.PI/2.5;
canvas.beginPath();
canvas.moveTo(cx+rx*Math.cos(0*step-Math.PI/2.), cy+ry*Math.sin(0*step-Math.PI/2.));
for(int i=1; i<=5; i++ ) {
canvas.lineTo(cx+rx*Math.cos(i*step-Math.PI/2.),cy+ry*Math.sin(i*step-Math.PI/2.));
}
canvas.closePath();
}
final static public void createHatDiamond(double x,double y,double w,double h,Canvas canvas){
canvas.beginPath();
createDiamond(x, y, w, h, canvas,false);
canvas.moveTo(x-2, y+h/2-2);
canvas.lineTo(x+w/2-2, y-2);
canvas.closePath();
}
final static public void createRHatDiamond(double x,double y,double w,double h,Canvas canvas){
canvas.beginPath();
createDiamond(x,y,w,h,canvas,false);
canvas.moveTo(x+w+2, y+h/2-2);
canvas.lineTo(x+w/2+2, y-2);
canvas.closePath();
}
final static public void createRhombus(double x,double y,double w,double h,Canvas canvas){
canvas.beginPath();
canvas.moveTo(x+0.50*w, y);
canvas.lineTo(x+0.85*w, y+0.50*h);
canvas.lineTo(x+0.50*w, y+h);
canvas.lineTo(x+0.15*w, y+0.50*h);
canvas.closePath();
}
//AS
final static public int midx(Rectangle r) {
return (r.x+(r.width/2));
}
//AS
final static public int midy(Rectangle r) {
return (r.y+(r.height/2));
}
public static void paintDashedLine(BasicCanvas canvas,int x1,int y1,int x2,int y2){
//This new implementation is based on the answers to the stackoverflow question below.
//http://stackoverflow.com/questions/4576724/dotted-stroke-in-canvas
int dx=(x2-x1);
int dy=(y2-y1);
//What's the orientation of the triangle, i.e. y steps x or x steps y
boolean xSlope=(Math.abs(dx) > Math.abs(dy));
//get the gradient y2-y1/x2-x1 or x2-x1/y2-y1
double gradient;
boolean xSlopeDown=false;
boolean ySlopeDown=false;
if(xSlope){
gradient=dy / (double) dx;
xSlopeDown=dx<0;
}else{
gradient=dx / (double) dy;
ySlopeDown=dy<0;
}
//convert to double for positioning
double x=x1;
double y=y1;
//Initial position
canvas.moveTo(x, y);
//The length of the dashed line "c" is equal to the square root of a^2+b^2
double dashedLineLength=Math.sqrt(dx*dx+dy*dy);
//how much of the line is left to go
double distRemaining=dashedLineLength;
boolean penUpOperation=false;
int dashLineLength=2;
int numDashes=(int) (dashedLineLength / dashLineLength);
if(dashedLineLength % dashLineLength >0){
numDashes++;
}
for(int i=0;i<numDashes;i++){
double dashLength=Math.min(distRemaining, dashLineLength); //set dashLine length to either the default or what ever is left
//calculate where x2 and y2 are based on c (dash length) and the gradient we need on the dashed line
double step=Math.sqrt(dashLength*dashLength / (1+gradient*gradient));
if(xSlope){
if(xSlopeDown){
step=-step;
}
x+=step;
y+=gradient*step;
}else{
if(ySlopeDown){
step=-step;
}
x+=gradient*step;
y+=step;
}
if(penUpOperation){
canvas.moveTo(x, y);
}else{
canvas.lineTo(x, y);
}
distRemaining-=dashLength;
penUpOperation=!penUpOperation;
}
}
static public void createEnd(BasicCanvas canvas,double angle, double x, double y, double w, double h) {
double rx = w/2.;
double ry = h/2.;
double cx = x+w/2.;
double cy = y+h/2.;
// start point
double x1 = cx+rx*Math.cos(angle-Math.PI/2.);
double y1 = cy+ry*Math.sin(angle-Math.PI/2.);
// end point
double x2 = cx+rx*Math.cos(angle+Math.PI/2.);
double y2 = cy+ry*Math.sin(angle+Math.PI/2.);
// ctrl point 1
double cx1 = cx+0.5*rx*Math.cos(angle-Math.PI/2.);
double cy1 = cy+0.5*ry*Math.sin(angle-Math.PI/2.);
double tx1 = cx1+0.5*rx*Math.cos(angle-Math.PI);
double ty1 = cy1+0.5*ry*Math.sin(angle-Math.PI);
// ctrl point 2
double cx2 = cx+0.5*rx*Math.cos(angle+Math.PI/2.);
double cy2 = cy+0.5*ry*Math.sin(angle+Math.PI/2.);
double tx2 = cx2+0.5*rx*Math.cos(angle);
double ty2 = cy2+0.5*ry*Math.sin(angle);
canvas.beginPath();
canvas.moveTo(x1, y1);
canvas.bezierCurveTo(tx1, ty1, tx2, ty2, x2, y2);
canvas.stroke();
canvas.closePath();
}
public static void createBracket(BasicCanvas canvas,double angle, double x, double y, double w, double h) {
double rx = w/2.;
double ry = h/2.;
double cx = x+w/2.;
double cy = y+h/2.;
// first start point
double x11 = cx+rx*Math.cos(angle-Math.PI/2.)+0.2*rx*Math.cos(angle);
double y11 = cy+ry*Math.sin(angle-Math.PI/2.)+0.2*ry*Math.sin(angle);
// first ctrl point 1
double tx11 = cx+0.9*rx*Math.cos(angle-Math.PI/2.)+0.2*rx*Math.cos(angle-Math.PI);
double ty11 = cy+0.9*ry*Math.sin(angle-Math.PI/2.)+0.2*ry*Math.sin(angle-Math.PI);
// first ctrl point 2;
double tx21 = cx+0.1*rx*Math.cos(angle-Math.PI/2.)+0.2*rx*Math.cos(angle);
double ty21 = cy+0.1*ry*Math.sin(angle-Math.PI/2.)+0.2*ry*Math.sin(angle);
// first end point
double x21 = cx+0.2*rx*Math.cos(angle-Math.PI);
double y21 = cy+0.2*ry*Math.sin(angle-Math.PI);
canvas.beginPath();
canvas.moveTo(x11, y11);
canvas.bezierCurveTo(tx11, ty11, tx21, ty21, x21, y21);
canvas.stroke();
canvas.closePath();
// second start point
double x12 = cx+rx*Math.cos(angle+Math.PI/2.)+0.2*rx*Math.cos(angle);
double y12 = cy+ry*Math.sin(angle+Math.PI/2.)+0.2*ry*Math.sin(angle);
// second ctrl point 1
double tx12 = cx+0.9*rx*Math.cos(angle+Math.PI/2.)+0.2*rx*Math.cos(angle-Math.PI);
double ty12 = cy+0.9*ry*Math.sin(angle+Math.PI/2.)+0.2*ry*Math.sin(angle-Math.PI);
// second ctrl point 2;
double tx22 = cx+0.1*rx*Math.cos(angle+Math.PI/2.)+0.2*rx*Math.cos(angle);
double ty22 = cy+0.1*ry*Math.sin(angle+Math.PI/2.)+0.2*ry*Math.sin(angle);
// second end point
double x22 = cx+0.2*rx*Math.cos(angle-Math.PI);
double y22 = cy+0.2*ry*Math.sin(angle-Math.PI);
canvas.beginPath();
canvas.moveTo(x12, y12);
canvas.bezierCurveTo(tx12, ty12, tx22, ty22, x22, y22);
canvas.stroke();
canvas.closePath();
}
static public void createSquareBracket(BasicCanvas canvas,double angle, double x, double y, double w, double h) {
double r = Math.min(w,h);
double cx = x+w/2.;
double cy = y+h/2.;
// first point
double x1 = cx+r*Math.cos(angle-Math.PI/2.)+r/4.*Math.cos(angle+Math.PI);
double y1 = cy+r*Math.sin(angle-Math.PI/2.)+r/4.*Math.sin(angle+Math.PI);
canvas.beginPath();
canvas.moveTo(x1, y1);
// second point
double x2 = cx+r*Math.cos(angle-Math.PI/2.);
double y2 = cy+r*Math.sin(angle-Math.PI/2.);
canvas.lineTo(x2, y2);
// third point
double x3 = cx+r*Math.cos(angle+Math.PI/2.);
double y3 = cy+r*Math.sin(angle+Math.PI/2.);
canvas.lineTo(x3, y3);
// fourth point
double x4 = cx+r*Math.cos(angle+Math.PI/2.)+r/4.*Math.cos(angle+Math.PI);
double y4 = cy+r*Math.sin(angle+Math.PI/2.)+r/4.*Math.sin(angle+Math.PI);
canvas.lineTo(x4, y4);
// close shape
canvas.lineTo(x3, y3);
canvas.lineTo(x2, y2);
}
}