/***********************************************************************
* mt4j Copyright (c) 2008 - 2010 Christopher Ruff, Fraunhofer-Gesellschaft All rights reserved.
*
* 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 org.mt4j.util;
import java.util.ArrayList;
import java.util.List;
import org.mt4j.components.TransformSpace;
import org.mt4j.components.bounds.BoundsZPlaneRectangle;
import org.mt4j.components.bounds.IBoundingShape;
import org.mt4j.components.visibleComponents.shapes.AbstractShape;
import org.mt4j.components.visibleComponents.shapes.MTComplexPolygon;
import org.mt4j.components.visibleComponents.shapes.MTPolygon;
import org.mt4j.util.math.ConvexityUtil;
import org.mt4j.util.math.ToolsGeometry;
import org.mt4j.util.math.Vertex;
import org.mt4j.util.xml.svg.CustomPathHandler;
import processing.core.PApplet;
public class ShapeBuilder {
private CustomPathHandler pathHandler;
private PApplet app;
public ShapeBuilder(PApplet app){
this.app = app;
this.pathHandler = new CustomPathHandler();
}
// public void startPath() throws ParseException {
// this.pathHandler.startPath();
// }
public void reset(){
this.pathHandler = new CustomPathHandler();
}
/**
* Starts a new path at the specified absolute coordinate.
*
* @param x the x
* @param y the y
*/
public void movetoAbs(float x, float y){
this.pathHandler.movetoAbs(x, y);
}
/**
* Starts a new path at the specified coordinate relative to the last coordinate.
*
* @param x the x
* @param y the y
*/
public void movetoRel(float x, float y){
this.pathHandler.movetoRel(x, y);
}
public void arcAbs(float rx, float ry, float phi, boolean largeArc, boolean sweep, float x, float y) {
this.pathHandler.arcAbs(rx, ry, phi, largeArc, sweep, x, y);
}
public void arcRel(float rx, float ry, float phi, boolean largeArc,boolean sweep, float x, float y) {
this.pathHandler.arcRel(rx, ry, phi, largeArc, sweep, x, y);
}
public void curvetoCubicAbs(float x1, float y1, float x2, float y2,float x, float y){
this.pathHandler.curvetoCubicAbs(x1, y1, x2, y2, x, y);
}
public void curvetoCubicRel(float x1, float y1, float x2, float y2,float x, float y) {
this.pathHandler.curvetoCubicRel(x1, y1, x2, y2, x, y);
}
public void curvetoCubicSmoothAbs(float x2, float y2, float x, float y){
this.pathHandler.curvetoCubicSmoothAbs(x2, y2, x, y);
}
public void curvetoCubicSmoothRel(float x2, float y2, float x, float y){
this.pathHandler.curvetoCubicSmoothRel(x2, y2, x, y);
}
public void curvetoQuadraticAbs(float x1, float y1, float x, float y) {
this.pathHandler.curvetoQuadraticAbs(x1, y1, x, y);
}
public void curvetoQuadraticRel(float x1, float y1, float x, float y){
this.pathHandler.curvetoQuadraticRel(x1, y1, x, y);
}
public void curvetoQuadraticSmoothAbs(float x, float y){
this.pathHandler.curvetoQuadraticSmoothAbs(x, y);
}
public void curvetoQuadraticSmoothRel(float x, float y) {
this.pathHandler.curvetoQuadraticSmoothRel(x, y);
}
public void linetoAbs(float x, float y){
this.pathHandler.linetoAbs(x, y);
}
public void linetoHorizontalAbs(float x){
this.pathHandler.linetoHorizontalAbs(x);
}
public void linetoHorizontalRel(float x){
this.pathHandler.linetoHorizontalRel(x);
}
public void linetoRel(float x, float y){
this.pathHandler.linetoRel(x, y);
}
public void linetoVerticalAbs(float y){
this.pathHandler.linetoVerticalAbs(y);
}
public void linetoVerticalRel(float y){
this.pathHandler.linetoVerticalRel(y);
}
public void setVerbose(boolean verbose) {
this.pathHandler.setVerbose(verbose);
}
/**
* Closed the current path by adding the start point again.
*/
public void closePath(){
this.pathHandler.closePath();
}
private void endPath(){
this.pathHandler.endPath();
}
public AbstractShape getShape(){
this.endPath();
ArrayList<Vertex[]> contours = this.pathHandler.getContours();
Vertex[] allPoints = this.pathHandler.getPathPointsArray();
AbstractShape returnComponent = null;
//Check for convexity
int convexity = ConvexityUtil.classifyPolygon2(allPoints.length, allPoints);
switch (convexity) {
case ConvexityUtil.NotConvexDegenerate:
// logger.debug("not Convex Degenerate");
case ConvexityUtil.NotConvex:
// logger.debug("not convex");
returnComponent = createComplexPoly(contours, MTComplexPolygon.WINDING_RULE_ODD);
break;
case ConvexityUtil.ConvexDegenerate:
// logger.debug("convex degenerate");
case ConvexityUtil.ConvexCW:
// logger.debug("convex clockwise");
case ConvexityUtil.ConvexCCW:
// logger.debug("convex counterclockwise");
returnComponent = createPoly(allPoints);
break;
default:
break;
}
//Create some default texture coords
if (returnComponent != null && returnComponent.hasBounds() && returnComponent.getBounds() instanceof BoundsZPlaneRectangle){
BoundsZPlaneRectangle bounds = (BoundsZPlaneRectangle) returnComponent.getBounds();
float width = bounds.getWidthXY(TransformSpace.LOCAL);
float height = bounds.getHeightXY(TransformSpace.LOCAL);
float upperLeftX = bounds.getVectorsLocal()[0].x;
float upperLeftY = bounds.getVectorsLocal()[0].y;
Vertex[] verts = returnComponent.getVerticesLocal();
for (int i = 0; i < verts.length; i++) {
Vertex vertex = verts[i];
vertex.setTexCoordU((vertex.x-upperLeftX)/width);
vertex.setTexCoordV((vertex.y-upperLeftY)/height);
//System.out.println("TexU:" + vertex.getTexCoordU() + " TexV:" + vertex.getTexCoordV());
}
returnComponent.getGeometryInfo().updateTextureBuffer(returnComponent.isUseVBOs());
}
return returnComponent;
}
private AbstractShape createPoly(Vertex[] verts) {
int segments = 15;
if (ToolsGeometry.containsBezierVertices(verts))
verts = ToolsGeometry.createVertexArrFromBezierArr(verts, segments);
//Blow up vertex array, that will be used for picking etc
//to at least be of size == 3 for generating normals
if (verts.length <3){
Vertex[] newVerts = new Vertex[3];
if (verts.length == 2){
newVerts[0] = verts[0];
newVerts[1] = verts[1];
newVerts[2] = (Vertex)verts[1].getCopy();
verts = newVerts;
}else if (verts.length == 1){
newVerts[0] = verts[0];
newVerts[1] = (Vertex)verts[0].getCopy();
newVerts[2] = (Vertex)verts[0].getCopy();
verts = newVerts;
}else{
//ERROR
}
}
MTPolygon poly = new MTPolygon2D(verts, app);
return poly;
}
private AbstractShape createComplexPoly(ArrayList<Vertex[]> contours, int windingRuleOdd) {
int segments = 15;
List<Vertex[]> bezierContours = ToolsGeometry.createVertexArrFromBezierVertexArrays(contours, segments);
MTComplexPolygon2D complexPoly = new MTComplexPolygon2D(app, bezierContours);
return complexPoly;
}
private class MTComplexPolygon2D extends MTComplexPolygon{
public MTComplexPolygon2D(PApplet app, List<Vertex[]> contours) {
super(app, contours);
}
@Override
protected IBoundingShape computeDefaultBounds() {
//Use z plane bounding rect instead default boundingsphere since always 2D!
return new BoundsZPlaneRectangle(this);
}
}
private class MTPolygon2D extends MTPolygon{
public MTPolygon2D(Vertex[] vertices, PApplet applet) {
super(vertices, applet);
}
protected IBoundingShape computeDefaultBounds() {
//Use z plane bounding rect instead default boundingsphere since always 2D!
return new BoundsZPlaneRectangle(this);
}
}
}