/* * Copyright (C) 2013 Steelkiwi Development, Julia Zudikova * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package com.steelkiwi.patheditor.path; import java.util.ArrayList; import com.badlogic.gdx.graphics.Color; import com.badlogic.gdx.graphics.glutils.ShapeRenderer; import com.badlogic.gdx.math.CatmullRomSpline; import com.badlogic.gdx.math.Vector3; import com.steelkiwi.patheditor.gdx.SplineBuilder.renderMode; public class PathSpline { public static final int SPLINE_MIN_VERTICES_COUNT = 4; private CatmullRomSpline spline; //catmullrom spline private ArrayList<Vector3> controlVertices; //spline's control vertices private Vector3[] totalVertices; //spline's whole vertices (control points + intermediate points) private ArrayList<Vector3> tangentsNormal; //vertices tangents normals private int segmentPointsCount = 1; public PathSpline() { spline = new CatmullRomSpline(); controlVertices = new ArrayList<Vector3>(); } public void addSplineControlVertex(float pX, float pY) { controlVertices.add(new Vector3(pX, pY, 0f)); updateSpline(); } public void updateSplineControlVertex(int index, float pX, float pY) { if (controlVertices == null) { return; } if ((index < 0) || (index >= getSplineControlVerticesCount())) { return; } controlVertices.get(index).set(new Vector3(pX, pY, 0f)); updateSpline(); } public void insertSplineControlVertex(int index1, int index2, float pX, float pY) { if (controlVertices == null) { return; } if ((index1 < 0) || (index1 >= getSplineControlVerticesCount())) { return; } if ((index2 < 0) || (index2 >= getSplineControlVerticesCount())) { return; } addSplineControlVertex(controlVertices.get(getSplineControlVerticesCount()-1).x, controlVertices.get(getSplineControlVerticesCount()-1).y); for (int i=getSplineControlVerticesCount()-3; i>=index2; i--) { updateSplineControlVertex(i+1, controlVertices.get(i).x, controlVertices.get(i).y); } updateSplineControlVertex(index2, pX, pY); } public void removeSplineControlVertex(int index) { if (controlVertices == null) { return; } if ((index < 0) || (index >= getSplineControlVerticesCount())) { return; } controlVertices.remove(index); updateSpline(); } private void updateSpline() { //clear old spline spline.getControlPoints().clear(); //set new control vertices for (int i=0; i<getSplineControlVerticesCount(); i++) { spline.add(controlVertices.get(i)); } if (getSplineControlVerticesCount() < SPLINE_MIN_VERTICES_COUNT) { return; } //generate all vertices (tip: spline creation needs two extra points) if (totalVertices != null) { totalVertices = null; } totalVertices = new Vector3[(((getSplineControlVerticesCount() - 2) - 1) * (segmentPointsCount + 2)) - ((getSplineControlVerticesCount() - 2) - 2)]; for (int i=0; i<getSplineVerticesCount(); i++) { totalVertices[i] = new Vector3(); } spline.getPath(totalVertices, segmentPointsCount); //get tangent normals for all vertices (+1 to get tangent normal for the last path vertex) if (tangentsNormal != null) { tangentsNormal.clear(); tangentsNormal = null; } tangentsNormal = (ArrayList<Vector3>) spline.getTangentNormals2D(segmentPointsCount+1); } public int getNearestSplineControlVertexIndex(float x, float y) { if (controlVertices == null) { return -1; } float nearestDistance = Float.MAX_VALUE; float tempDistance; int nearestIndex = -1; for (int i=0; i<getSplineControlVerticesCount(); i++) { tempDistance = Math.abs(x - controlVertices.get(i).x); if (tempDistance < nearestDistance) { nearestIndex = i; nearestDistance = tempDistance; } } return nearestIndex; } public Vector3 getSplineControlVertexByIndex(int index) { if (controlVertices == null) { return null; } if ((index < 0) || (index >= getSplineControlVerticesCount())) { return null; } return controlVertices.get(index); } public ArrayList<Vector3> getSplineControlVertices() { return controlVertices; } public int getSplineControlVerticesCount() { if (controlVertices == null) { return 0; } return controlVertices.size(); } public Vector3 getSplineVertexByIndex(int index) { if (totalVertices == null) { return null; } if ((index < 0) || (index >= getSplineVerticesCount())) { return null; } return totalVertices[index]; } public int getSplineVerticesCount() { if (totalVertices == null) { return 0; } return totalVertices.length; } public Vector3 getSplineVertexTangentNormalByIndex(int index) { if (tangentsNormal == null) { return null; } if ((index < 0) || (index >= tangentsNormal.size())) { return null; } return tangentsNormal.get(index); } public int getSplineVerticesTangentNormalsCount() { if (tangentsNormal == null) { return -1; } return tangentsNormal.size(); } public int getSplineSegmentVerticesCount() { return segmentPointsCount; } public void setSplineSegmentPointsCount(int segmentPointsCount) { this.segmentPointsCount = segmentPointsCount; } public void present(ShapeRenderer renderer, int index, int leftIndex, int rightIndex, renderMode mode, Color controlColor, Color segmentColor, Color selectColor) { Vector3 v; //draw all vertices if (totalVertices != null) { for (int i=0; i<getSplineVerticesCount()-1; i++) { v = totalVertices[i]; renderer.setColor(segmentColor); renderer.filledCircle(v.x, v.y, 4); } } //draw control vertices if (controlVertices != null) { for (int i=0; i<controlVertices.size(); i++) { v = controlVertices.get(i); renderer.setColor(controlColor); renderer.filledCircle(v.x, v.y, 4); } } //draw currently selected vertex if ((index != -1) || ((leftIndex != -1) || (rightIndex != -1))) { if ((mode == renderMode.EDIT) || (mode == renderMode.INSERT)) { if (controlVertices != null) { for (int i=0; i<controlVertices.size(); i++) { if (mode == renderMode.EDIT) { if (i == index) { v = controlVertices.get(i); renderer.setColor(selectColor); renderer.filledCircle(v.x, v.y, 8); } } if (mode == renderMode.INSERT) { if (i == leftIndex) { v = controlVertices.get(i); renderer.setColor(selectColor); renderer.filledCircle(v.x, v.y, 8); } if (i == rightIndex) { v = controlVertices.get(i); renderer.setColor(selectColor); renderer.filledCircle(v.x, v.y, 8); } } } } } } } public void clearSpline() { if (controlVertices != null) { controlVertices.clear(); } totalVertices = null; if (tangentsNormal != null) { tangentsNormal.clear(); } } public void setSplineControlVertices(ArrayList<Vector3> controlVertices) { if (this.controlVertices != null) { this.controlVertices.clear(); this.controlVertices = null; } if (controlVertices == null) { return; } this.controlVertices = new ArrayList<Vector3>(); Vector3 v; for (int i=0; i<controlVertices.size(); i++) { v = controlVertices.get(i); this.controlVertices.add(new Vector3(v.x, v.y, 0f)); } updateSpline(); } }