package com.pixelmaid.dresscode.drawing.primitive2d;
import java.util.ArrayList;
import java.util.Collections;
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;
import com.pixelmaid.dresscode.events.CustomEvent;
public class Polygon extends Drawable implements PrimitiveInterface, Turtle{
protected ArrayList<Point> points;
private int sideNum = 0;
private double sideLength = 0;
//private ArrayList<Hole> holes;
boolean closed = true;
private static double DEFAULT_LENGTH = 20;
public Polygon(){
this(0,0);
}
public Polygon(Point o){
this.origin=o;
points= new ArrayList<Point>();
// holes = new ArrayList<Hole>();
}
public Polygon(int sides, double length){
this(0,0,sides,length);
}
public Polygon(double x, double y, int sides){
this(x,y,sides,DEFAULT_LENGTH);
}
public Drawable setRadius(double r,int sides){
this.clearPoints();
sideNum = sides;
sideLength = 2*r*Math.sin(Math.toRadians(180/sides));
for(int i=0;i<sides;i++){
double theta = 360/sides*i;
Point p = new Point(0,0,Math.toRadians(theta)+Math.PI/2 - Math.PI/sides,r);
this.addPoint(p);
}
return this;
}
public Polygon(double x, double y,int sides, double length){
this(new Point(x,y));
sideNum = sides;
sideLength = length;
if(sides!=0){
double a = length/(2*Math.sin(Math.toRadians(180/sides)));
for(int i=0;i<sides;i++){
double theta = 360/sides*i;
Point p = new Point(0,0,Math.toRadians(theta)+Math.PI/2 - Math.PI/sides,a);
this.addPoint(p);
}
//this.setPointsAbsolute();
//this.setPointsRelativeTo(new Point(0,0));
}
/*double angle = 360/(double)sides;
resetTurtle();
for(int i=0;i<sides;i++){
this.forward(length);
this.right(angle);
}*/
}
/*public void addHole(Hole h){
h.setParent(this);
holes.add(h);
}*/
public Polygon(ArrayList<Point> pts) {
this(new Point(0,0));
this.points=pts;
this.setOrigin(Geom.findCentroid(this));
this.setPointsRelativeTo(this.getOrigin());
}
public void addPoint(Double x, Double y){
addPoint(new Point(x,y));
}
protected void addPoint(Point point){
this.points.add(point);
}
public void addDynamicPoint(Point point){
System.out.println("=======================\n starting number of points"+this.points.size());
if(this.points.size()>1){
/*System.out.println("\n before set absolute");
for(int i=0;i<points.size();i++){
System.out.println(points.get(i).getX()+","+points.get(i).getY());
}*/
this.setPointsAbsolute();
/*
System.out.println("\n after set absolute");
System.out.println("number of points"+this.points.size());
for(int i=0;i<points.size();i++){
System.out.println(points.get(i).getX()+","+points.get(i).getY());
}
System.out.println("\n adding point at: "+point.getX()+","+point.getY());
*/
this.points.add(point);
///System.out.println("number of points"+this.points.size());
this.setOrigin(Geom.findCentroid(this));
/*System.out.println("\n after find centroid");
System.out.println("\n centroid at: "+origin.getX()+","+origin.getY());
System.out.println("number of points"+this.points.size());*/
this.setPointsRelativeTo(this.getOrigin());
/*System.out.println("\n after set relative");
System.out.println("number of points"+this.points.size());
for(int i=0;i<points.size();i++){
System.out.println(points.get(i).getX()+","+points.get(i).getY());
}*/
}
else{
this.points.add(point);
}
}
public void reversePoints(){
Collections.reverse(this.points);
}
public void clearPoints(){
this.points.clear();
}
public void addAllPoints(Polygon p) {
this.points.addAll(p.getPoints());
}
public ArrayList<Point> getPoints(){
return this.points;
}
public void setPoints(ArrayList<Point> p){
this.points = p;
}
//determines if polygon is closed or not
public void setClosed(boolean c){
closed = c;
}
@Override
public Drawable mirrorX(Point focus, Boolean top){
this.setPointsAbsolute();
for(int i=0;i<points.size();i++){
Point p = points.get(i);
double delta = focus.getX()-p.getX();
double xNew = focus.getX()+delta;
points.set(i, new Point(xNew,p.getY()));
}
this.reversePoints();
if(top){
resetOriginRecur();
}
return this;
}
@Override
public Drawable mirrorY(Point focus, Boolean top){
this.setPointsAbsolute();
for(int i=0;i<points.size();i++){
Point p = points.get(i);
double delta = focus.getY()-p.getY();
double yNew = focus.getY()+delta;
points.set(i, new Point(p.getX(),yNew));
}
this.reversePoints();
if(top){
resetOriginRecur();
}
return this;
}
@Override
//flattens multi-dimensional groups into 1 dimension
public Drawable flatten(boolean top,Drawable d){
if(top){
this.flattenedDrawable = d;
}
System.out.println("flattening polygon");
this.setAbsolute();
d.add(this);
return this;
}
@Override
//rotates around a focus. does not change the rotation property
public Drawable rotateWithFocus(double theta, Point focus, Boolean top){
this.setPointsAbsolute();
for(int i=0;i<this.points.size();i++){
Point newPoint = this.points.get(i).rotate(theta, focus);
this.points.set(i,newPoint);
}
if(top){
resetOriginRecur();
}
return this;
}
public void resetOriginRecur(){
if(this.isHole()){
this.reversePoints();
}
this.setOrigin(Geom.findCentroid(this));
if(this.isHole()){
this.reversePoints();
}
this.setPointsRelativeTo(this.getOrigin());
}
//===================OVERRIDDEN METHODS==================
@Override
public void draw(Canvas e){
if(!this.getHide()){
appearance(e.g);
if(this.getSelected()){
e.strokeWeight(2);
e.stroke(Drawable.SELECTED.r(),Drawable.SELECTED.g(),Drawable.SELECTED.b());
}
if(isHole()){
e.fill(e.DEFAULT_BG);
}
//System.out.println("number of holes="+this.holes.size()+"number of points="+this.points.size());
e.pushMatrix();
e.translate((float)(getOrigin().getX()),(float)(getOrigin().getY()));
e.rotate(PApplet.radians((float)getRotation()));
e.beginShape();
for(int i=0;i<points.size();i++){
e.vertex((float)points.get(i).getX(),(float)points.get(i).getY());
}
if(!closed){
e.endShape(PApplet.OPEN);
}
else{
e.endShape(PApplet.CLOSE);
}
e.popMatrix();
/*if(this.getDrawOrigin()){
this.drawOrigin(e);
}*/
}
}
@Override
public void print(PGraphics e){
if(!this.getHide()){
appearance(e);
e.noFill();
//System.out.println("number of holes="+this.holes.size()+"number of points="+this.points.size());
e.pushMatrix();
e.translate((float)(getOrigin().getX()),(float)(getOrigin().getY()));
e.rotate(PApplet.radians((float)getRotation()));
e.scale((float)getScaleX(),(float)getScaleY());
e.beginShape();
for(int i=0;i<points.size();i++){
e.vertex((float)points.get(i).getX(),(float)points.get(i).getY());
}
e.endShape(PApplet.CLOSE);
e.popMatrix();
}
}
@Override
public Polygon copy(){
Polygon c = new Polygon();
copyParameters(this, c);
this.setParent(this.getParent());
for(int i=0;i<points.size();i++){
c.addPoint(points.get(i).copy());
}
if (this.isHole()){
c.toHole();
}
return c;
}
//converts polygon to hole
public void toHole(){
this.isHole = true;
}
//converts hole to poly
public void toPoly(){
this.isHole = false;
}
@Override
//scales the object on the x axis
public Drawable scale(double x, double y, Point focus, Boolean top ) {
this.setPointsAbsolute();
for(int i=0;i<points.size();i++){
Point p = points.get(i);
System.out.println("startX ="+p.getX());
Vec2d vX = new Vec2d(p.getX()-focus.getX(),p.getY()-focus.getY());
vX = vX.mul(x);
p.setX(vX.x+focus.getX());
Vec2d vY = new Vec2d(p.getX()-focus.getX(),p.getY()-focus.getY());
vY = vY.mul(y);
p.setY(vY.y+focus.getY());
//p.setY(v.y+this.getOrigin().getY());
points.set(i,p);
}
if(top){
resetOriginRecur();
}
return this;
}
@Override
//sets the points and holes relative around a new origin
public void setPointsRelativeTo(Point p) {
for(int i=0;i<this.points.size();i++){
Point newPoint = this.points.get(i);
this.points.set(i,newPoint.difference(p));
}
this.origin=p;
}
@Override
public Drawable expand(){
Drawable poly = new Drawable();
this.setPointsAbsolute();
double xLast =points.get(0).getX();
double yLast = points.get(0).getY();
for (int i = 1; i <= points.size(); i++) {
double x;
double y;
if(i<points.size()){
x=points.get(i).getX();
y=points.get(i).getY();
}
else{
x=points.get(0).getX();
y=points.get(0).getY();
}
Line l = new Line(xLast,yLast,x,y);
l.setStrokeWeight(this.getStrokeWeight());
Polygon p = (Polygon)l.expand();
poly.addToGroup(p);
xLast = x;
yLast = y;
}
//poly.setFillColor(this.getStrokeColor());
//poly.doStroke(false);
//return poly;
return PolyBoolean.merge(poly);
}
@Override
//sets all points to absolute position based on the origin of the object
public void setPointsAbsolute() {
//TODO: eventually need to deal with the fact that this should not contain setAbsolute
this.setAbsolute();
for(int i=0;i<this.points.size();i++){
Point pt = new Point(points.get(i).getX()+getOrigin().getX(),points.get(i).getY()+getOrigin().getY());
pt.rotate(getRotation(),getOrigin());
this.points.set(i,pt);
}
}
@Override
//returns itself (already is a polygon)
public Polygon toPolygon(){
//System.out.println("polygon to polygon");
return this;
}
@Override
// creates a new drawable and adds this polygon and d to it and returns new drawable
public Drawable addToGroup(Drawable d){
return this.addToGroup(d,1);
}
public Drawable addToGroup(Drawable d, int index){
Drawable master = new Drawable();
//TODO: adjust indexing here to have new drawable added at same index as this
this.fireDrawableEvent(CustomEvent.DRAWABLE_CREATED, master);
this.fireDrawableEvent(CustomEvent.REMOVE_DRAWABLE, d);
master.addToGroup(this);
master.addToGroup(d,index);
return master;
}
@Override
//overrides drawable remove from group method- returns a null value since a polygon cannot be a group by itself
public Drawable removeFromGroup(Drawable d){
//Window.output.setText("cannot remove from group from a polygon group");
System.err.println("cannot remove from group from a polygon group");
return null;
}
@Override
//overrides drawable remove all children method- returns a null value since a polygon does not have any children to remove
public ArrayList<Drawable> removeAllChildren(){
//Window.output.setText("cannot remove all children from a polygon");
System.err.println("cannot remove all children from a polygon");
return null;
}
@Override
// creates a new drawable and adds this polygon all orphans to it and returns new drawable
public Drawable addAllChildren(ArrayList<Drawable> orphans){
Drawable master = new Drawable();
//TODO: adjust indexing here to have new drawable added at same index as this
this.fireDrawableEvent(CustomEvent.DRAWABLE_CREATED, master);
this.fireDrawableEvent(CustomEvent.REMOVE_DRAWABLE, this);
master.addToGroup(this);
for(int i=0;i<orphans.size();i++){
master.addToGroup(orphans.get(i));
}
return master;
}
@Override
//returns child at a specific index- need to decide if should return a copy or child itself
public Point pointAt(int i){
this.setPointsAbsolute();
Point p = this.points.get(i).copy();
this.setPointsRelativeTo(this.origin);
return p;
}
@Override
//gets all points of all children
public ArrayList<Point> copyAllPoints(){
ArrayList<Point> copyPoints = new ArrayList<Point>();
for(int i=0;i<this.getPoints().size();i++){
copyPoints.add(this.getPoints().get(i).copy());
}
return copyPoints;
}
//=============================TURTLE METHODS==================================//
@Override
public void left(double angle) {
TurtleStruct.angle-=angle;
/*if(TurtleStruct.angle<0){
TurtleStruct.angle = 360;
}*/
}
@Override
public void right(double angle) {
// TODO Auto-generated method stub
TurtleStruct.angle+=angle;
/*if(TurtleStruct.angle>360){
TurtleStruct.angle = 0;
}*/
}
@Override
public void forward(double dist) {
Point point = Geom.polarToCart(dist, TurtleStruct.angle);
if(TurtleStruct.pen){
this.addPoint(point);
}
TurtleStruct.location =point;
}
@Override
public void back(double dist) {
Point point = Geom.polarToCart(-dist, TurtleStruct.angle);
if(TurtleStruct.pen){
this.addPoint(point);
}
TurtleStruct.location =point;
}
@Override
public void penUp() {
TurtleStruct.pen=false;
// TODO Auto-generated method stub
}
@Override
public void penDown() {
TurtleStruct.pen=true;
// TODO Auto-generated method stub
}
public void resetTurtle(){
TurtleStruct.angle = 0;
TurtleStruct.pen = true;
TurtleStruct.location = new Point(0,0);
}
public void moveTurtleTo(double x, double y){
TurtleStruct.location = new Point(x,y);
}
public void rotateTurtleTo(double theta){
TurtleStruct.angle = theta;
}
//returns number of sides
public int numSides() {
// TODO Auto-generated method stub
return sideNum;
}
//returns number of sides
public double sideLength() {
// TODO Auto-generated method stub
return sideLength;
}
}