package com.pixelmaid.dresscode.drawing.primitive2d;
import processing.core.PApplet;
import processing.core.PGraphics;
import com.pixelmaid.dresscode.app.Canvas;
import com.pixelmaid.dresscode.drawing.datatype.Point;
import com.pixelmaid.dresscode.drawing.math.Geom;
import com.pixelmaid.dresscode.drawing.math.PolyBoolean;
import com.pixelmaid.dresscode.drawing.math.Vec2d;
public class Curve extends Polygon { //series of symmetrical curved lines grouped together in a single line
private int resolution = 20; // resolution of each curve
private boolean showPoints = false;
public Point control1;
public Point control2;
public Point start;
public Point end;
//TODO: implement two point curve
//public Curve(double sX, double sY, double eX, double eY ){
//this(new Point(sX,sY),new Point(c1X,c1Y),new Point(c2X,c2Y),new Point(eX,eY));
//}
//initialize curve from 4 x/y coordinates values
public Curve(double[] values) {
this(values[0],values[1],values[2],values[3],values[4],values[5],values[6],values[7]);
}
public Curve(double sX, double sY, double c1X, double c1Y, double c2X, double c2Y, double eX, double eY ){
this(new Point(sX,sY),new Point(c1X,c1Y),new Point(c2X,c2Y),new Point(eX,eY));
}
public Curve(Point start, Point control1, Point control2, Point end){
this.start=start;
this.control1=control1;
this.control2=control2;
this.end=end;
this.origin= this.getOrigin();
this.doFill(false);
}
@Override
public void draw(Canvas e){
//TODO: MAKE CURVE DRAW ORIGIN CORRECTLY
if(!this.getHide()){
appearance(e.g);
if(this.getSelected()){
e.strokeWeight(2);
e.stroke(Drawable.SELECTED.r(),Drawable.SELECTED.g(),Drawable.SELECTED.b());
}
e.pushMatrix();
e.translate((float)(getOrigin().getX()),(float)(getOrigin().getY()));
e.rotate(PApplet.radians((float)getRotation()));
e.scale((float)getScaleX(),(float)getScaleY());
e.bezier((float)(start.getX()-getOrigin().getX()), (float)(start.getY()-getOrigin().getY()),(float)(control1.getX()-getOrigin().getX()), (float)(control1.getY()-getOrigin().getY()), (float)(control2.getX()-origin.getX()), (float)(control2.getY()-origin.getY()),(float)(end.getX()-origin.getX()), (float)(end.getY()-origin.getY()));
e.popMatrix();
}
}
@Override
public void drawOrigin(Canvas e){
e.stroke(0,0,0);
e.strokeWeight(8);
e.point((float)this.origin.getX(),(float)this.origin.getY());
e.stroke(255,255,255);
e.strokeWeight(4);
e.point((float)this.origin.getX(),(float)this.origin.getY());
e.pushMatrix();
e.translate((float)(getOrigin().getX()),(float)(getOrigin().getY()));
e.stroke(255,0,0);
e.strokeWeight(5);
e.point((float)(control1.getX()-getOrigin().getX()), (float)(control1.getY()-getOrigin().getY()));
e.stroke(0,0,255);
e.point((float)(control2.getX()-getOrigin().getX()), (float)(control2.getY()-getOrigin().getY()));
e.popMatrix();
}
@Override
public void print(PGraphics e){
//TODO: MAKE CURVE DRAW RELATIVE
if(!this.getHide()){
appearance(e);
e.noFill();
e.pushMatrix();
e.translate((float)(getOrigin().getX()),(float)(getOrigin().getY()));
e.rotate(PApplet.radians((float)getRotation()));
e.scale((float)getScaleX(),(float)getScaleY());
e.bezier((float)start.getX(), (float)start.getY(),(float)control1.getX(), (float)control1.getY(), (float)control2.getX(), (float)control2.getY(),(float)end.getX(), (float)end.getY());
e.popMatrix();
}
}
@Override
public Drawable setAbsolute() {
if(this.getParent()!=null){
this.start= this.start.add(this.getParent().getOrigin()); //add parent's origin to its origin
this.end= this.end.add(this.getParent().getOrigin()); //add parent's origin to its origin
this.control1= this.control1.add(this.getParent().getOrigin()); //add parent's origin to its origin
this.control2= this.control2.add(this.getParent().getOrigin()); //add parent's origin to its origin
this.rotation = (this.getRotation()+this.getParent().getRotation()); //adds parent's rotation to its rotation
}
return this;
}
@Override
public Curve copy(){
Curve c = new Curve(start.copy(),control1.copy(),control2.copy(),end.copy());
copyParameters(this,c);
return c;
}
@Override
//rotates around a focus. does not change the rotation property
public Drawable rotateWithFocus(double theta, Point focus, Boolean top){
this.setPointsAbsolute();
start= start.rotate(theta, focus);
end = end.rotate(theta, focus);
control1= control1.rotate(theta, focus);
control2 = control2.rotate(theta, focus);
if(top){
resetOriginRecur();
}
return this;
}
@Override
public Drawable mirrorX(Point focus, Boolean top){
this.setAbsolute();
Point p1 = start.copy();
Point p2 = end.copy();
Point c1 = control1.copy();
Point c2 = control2.copy();
double delta = focus.getX()-p1.getX();
double xNew = focus.getX()+delta;
start = new Point(xNew,p1.getY());
delta = focus.getX()-p2.getX();
xNew = focus.getX()+delta;
end = new Point(xNew,p2.getY());
delta = focus.getX()-c1.getX();
xNew = focus.getX()+delta;
control1 = new Point(xNew,c1.getY());
delta = focus.getX()-c2.getX();
xNew = focus.getX()+delta;
control2 = new Point(xNew,c2.getY());
this.origin= this.getOrigin();
if(top){
resetOriginRecur();
}
return this;
}
@Override
public Drawable mirrorY(Point focus, Boolean top){
this.setAbsolute();
Point p1 = start.copy();
Point p2 = end.copy();
Point c1 = control1.copy();
Point c2 = control2.copy();
double delta = focus.getY()-p1.getY();
double yNew = focus.getY()+delta;
start = new Point(p1.getX(),yNew);
delta = focus.getY()-p2.getY();
yNew = focus.getY()+delta;
end = new Point(p2.getX(),yNew);
delta = focus.getY()-c1.getY();
yNew = focus.getY()+delta;
control1 = new Point(c1.getX(),yNew);
delta = focus.getY()-c2.getY();
yNew = focus.getY()+delta;
control2 = new Point(c2.getX(),yNew);
this.origin= this.getOrigin();
if(top){
resetOriginRecur();
}
return this;
}
@Override
public Drawable scale(double x, double y, Point focus, Boolean top){
this.setAbsolute();
Point p1 = this.end.copy();
Point p2 = this.start.copy();
Point c1 = this.control1.copy();
Point c2 = this.control2.copy();
Vec2d vX = new Vec2d(p1.getX()-focus.getX(),p1.getY()-focus.getY());
vX = vX.mul(x);
p1.setX(vX.x+focus.getX());
Vec2d vY = new Vec2d(p1.getX()-focus.getX(),p1.getY()-focus.getY());
vY = vY.mul(y);
p1.setY(vY.y+focus.getY());
start=p1;
vX = new Vec2d(p2.getX()-focus.getX(),p2.getY()-focus.getY());
vX = vX.mul(x);
p2.setX(vX.x+focus.getX());
vY = new Vec2d(p2.getX()-focus.getX(),p2.getY()-focus.getY());
vY = vY.mul(y);
p2.setY(vY.y+focus.getY());
end=p2;
vX = new Vec2d(c1.getX()-focus.getX(),c1.getY()-focus.getY());
vX = vX.mul(x);
c1.setX(vX.x+focus.getX());
vY = new Vec2d(c1.getX()-focus.getX(),c1.getY()-focus.getY());
vY = vY.mul(y);
c1.setY(vY.y+focus.getY());
control1 = c1;
vX = new Vec2d(c2.getX()-focus.getX(),c2.getY()-focus.getY());
vX = vX.mul(x);
c2.setX(vX.x+focus.getX());
vY = new Vec2d(c2.getX()-focus.getX(),c2.getY()-focus.getY());
vY = vY.mul(y);
c2.setY(vY.y+focus.getY());
control2=c2;
this.getOrigin();
if(top){
resetOriginRecur();
}
return this;
}
@Override
public void resetOriginRecur(){
this.origin=this.getOrigin();
//this.setPointsRelativeTo(this.origin);
}
@Override
protected void setRelativeTo(Point p) {
this.start = this.start.difference(p);
this.end = this.end.difference(p);
this.control1 = this.control1.difference(p);
this.control2 = this.control2.difference(p);
this.getOrigin();
}
@Override
//converts ellipse to polygon
public Polygon toPolygon() {
Polygon poly = new Polygon();
copyParameters(this,poly);
for (int i = 0; i <= resolution; i++) {
float t = (float)i / (float)resolution;
PApplet p = new PApplet();
double x = p.bezierPoint((float)start.getX(), (float)control1.getX(), (float)control2.getX(), (float)end.getX(), t);
double y = p.bezierPoint((float)start.getY(), (float)control1.getY(), (float)control2.getY(), (float)end.getY(), t);
poly.addPoint(x,y);
}
poly.setPointsRelativeTo(this.getOrigin());
return poly;
}
@Override
public Drawable expand(){
Polygon poly = new Polygon();
double xLast =0;
double yLast = 0;
for (int i = 0; i <= resolution; i++) {
float t = (float)i / (float)resolution;
PApplet a = new PApplet();
a.init();
double x = a.bezierPoint((float)start.getX(), (float)control1.getX(), (float)control2.getX(), (float)end.getX(), t);
double y = a.bezierPoint((float)start.getY(), (float)control1.getY(), (float)control2.getY(), (float)end.getY(), t);
if(i>0){
Line l = new Line(xLast,yLast,x,y);
l.setStrokeWeight(this.getStrokeWeight());
Polygon p = (Polygon)l.expand();
if(i==1){
poly = p;
}
else{
poly = (Polygon) PolyBoolean.union(poly, p);
}
}
xLast = x;
yLast = y;
a.dispose();
a = null;
}
poly.setFillColor(this.getStrokeColor());
poly.doStroke(false);
return poly;
}
@Override
public Point getOrigin(){
this.origin= this.getMidPoint();
return this.origin;
}
public Point getMidPoint(){
return Geom.getMidpoint(this.start, this.end);
}
@Override
public void moveTo(double x, double y){
this.origin= this.getOrigin();
double dx = x - this.origin.getX();
double dy = y-this.origin.getY();
this.start.moveBy(dx,dy);
this.end.moveBy(dx,dy);
this.control1.moveBy(dx, dy);
this.control2.moveBy(dx, dy);
this.origin= this.getOrigin();
}
@Override
public void moveBy(double x, double y){
this.start.moveBy(x,y);
this.end.moveBy(x,y);
this.control1.moveBy(x, y);
this.control2.moveBy(x, y);
this.origin= this.getOrigin();
}
@Override
public Point pointAt(int i){
Polygon poly = this.toPolygon();
poly.setPointsAbsolute();
Point p = poly.getPoints().get(i).copy();
return p;
}
public Point getStart(){
return this.start.copy();
}
public Point getEnd(){
return this.end.copy();
}
public Point getControl1(){
return this.control1.copy();
}
public Point getControl2(){
return this.control2.copy();
}
public void setEnd(double x, double y) {
this.end = new Point(x,y);
}
public void setStart(double x, double y) {
this.start = new Point(x,y);
}
public void setControl1(double x, double y) {
this.control1 = new Point(x,y);
}
public void setControl2(double x, double y) {
this.control2 = new Point(x,y);
}
}