//////////////////// /// DRAWING METHODS /// DRAWING METHODS //////////////////// void DrawElement(ShapeElement element) { // Debug.Log("Drawing element . Points: " + element.knots.Length); for (int i = 0; i < element.knots.Length - 1; i++) { //CREATE A BEZIER SEGMENT BezierSegment seg = new BezierSegment(); seg.A = GetScaledVector(element.knots[i].KWorldPos(transform)); //START POINT seg.B = GetScaledVector(element.knots[i].KHandleOutWorldPos(transform)); //START TANGENT seg.C = GetScaledVector(element.knots[i + 1].KHandleInWorldPos(transform)); //END TANGENT seg.D = GetScaledVector(element.knots[i + 1].KWorldPos(transform)); //END POINT //NON SCALED /* * //CREATE A BEZIER SEGMENT * BezierSegment seg = new BezierSegment(); * seg.A = element.knots[i].KWorldPos(transform); //START POINT * seg.B = element.knots[i].KHandleOutWorldPos(transform); //START TANGENT * seg.C = element.knots[i + 1].KHandleInWorldPos(transform); //END TANGENT * seg.D = element.knots[i + 1].KWorldPos(transform); //END POINT */ //Draw it DrawBezierSegment(seg); } }
/// <summary> /// Gets the sum of all individuals segments in this curve /// </summary> /// <returns></returns> public static float GetCurveLength(ShapeElement element, Transform theT) { float TotalLenghtSum = 0; //Draw Each Element for (int i = 0; i < element.knots.Length - 1; i++) { //CREATE A BEZIER SEGMENT BezierSegment seg = new BezierSegment(); seg.A = element.knots[i].KWorldPos(theT); //START POINT seg.B = element.knots[i].KHandleOutWorldPos(theT); //START TANGENT seg.C = element.knots[i + 1].KHandleInWorldPos(theT); //END TANGENT seg.D = element.knots[i + 1].KWorldPos(theT); //END POINT float totalLength = GetLengthSimpsons(0f, 1f, seg); TotalLenghtSum = TotalLenghtSum + totalLength; } return(TotalLenghtSum); }
void DrawElementHandles(ShapeElement element) { // Debug.Log("Drawing element . Points: " + element.knots.Length); //DRAW KNOTS for (int i = 0; i < element.knots.Length; i++) { if (element.knots[i].isSelected) //if (element.knots[i] == Target.selectedKnot) { DrawKnotMovementHandle(element.knots[i]); switch (element.knots[i].kType) { case KnotType.Linear: break; case KnotType.Smooth: break; case KnotType.Bezier: DrawKnotBezierHandles(element.knots[i], true, true); break; default: break; } //if (element.knots[i].kType == KnotType.Bezier || element.knots[i].kType == KnotType.Smooth) //{ // DrawKnotBezierHandles(element.knots[i], true, true); // } } else { DrawKnotSelector(element.knots[i]); } } }
//////////////////////////////////////// /// INITIALIZATION /// INITIALIZATION //////////////////////////////////////// void CreateDefaultCurve() { //Reset the elements Array elements = new ShapeElement[1]; //Add an element to the array elements[0] = new ShapeElement(); //Create the Knot Array elements[0].knots = new ShapeKnot[2]; //Create the first knot elements[0].knots[0] = new ShapeKnot(); //Setup the element Index elements[0].knots[0].myElementIndex = 0; //Setup knot index elements[0].knots[0].myIndex = 0; //Position of the first knot elements[0].knots[0].kPos = new Vector3(0, 0, -5); //Handle in of the first Knot elements[0].knots[0].kHandleIn = new Vector3(0, 0, -2); //Handle out of the first Knot elements[0].knots[0].kHandleOut = new Vector3(0, 0, 2); //Create the second knot elements[0].knots[1] = new ShapeKnot(); //Setup the element Index elements[0].knots[1].myElementIndex = 0; //Setup knot index elements[0].knots[1].myIndex = 1; //Position of the second knot elements[0].knots[1].kPos = new Vector3(0, 0, 5); //Handle in of the second Knot elements[0].knots[1].kHandleIn = new Vector3(0, 0, -2); //Handle out of the second Knot elements[0].knots[1].kHandleOut = new Vector3(0, 0, 2); }
//////////////////////////////////////// /// SPLINE UPDATE /// SPLINE UPDATE //////////////////////////////////////// /* RECALCULATE LINEAR * In this mode the Control Points ( tangents) go half-way the distance between them ant their neighbouring control point * tangentIn of knot[n] will go half way toward knot[n-1].tangentOut * tangentOut of knot[n] will go half way toward knot[n+1].tangentIn */ void RecalculateLinearKnot(ShapeElement element, int knotIndex) { //Debug.Log("recalculating index " + knotIndex.ToString()); //Local Variables Vector3 knotWorldPos = element.knots[knotIndex].KWorldPos(transform); Vector3 tempWorldPos = Vector3.zero; bool calculateOutHandle = !(knotIndex == element.knots.Length - 1); bool calculateInHandle = !(knotIndex == 0); if (calculateOutHandle) { Vector3 handleOutTarget = element.knots[knotIndex + 1].KHandleInWorldPos(transform); tempWorldPos = Vector3.Lerp(knotWorldPos, handleOutTarget, 0.5f); element.knots[knotIndex].kHandleOut = tempWorldPos - knotWorldPos; } if (calculateInHandle) { Vector3 handleInTarget = element.knots[knotIndex - 1].KHandleOutWorldPos(transform); tempWorldPos = Vector3.Lerp(knotWorldPos, handleInTarget, 0.5f); element.knots[knotIndex].kHandleIn = tempWorldPos - knotWorldPos; } }
//Divide the curve into equal steps public static List <Vector3> ResampleCurve(int numSteps, ShapeElement element, Transform theT) { float totalLenght = GetCurveLength(element, theT); float sectionLength = totalLenght / numSteps; List <Vector3> curveSteps = new List <Vector3>(); /* * 20 8 35 17 -segmentLenghts N * * X -------------X--------X-------------------X-----------X -theSegs N * * 0 20 28 63 80 -knotDistances N+1 * */ //Create A list of Bezier Segment List <BezierSegment> theSegs = new List <BezierSegment>(); //Create A list of Bezier Segment Lengths List <float> segmentLenghts = new List <float>(); for (int i = 0; i < element.knots.Length - 1; i++) { //CREATE A BEZIER SEGMENT BezierSegment seg = new BezierSegment(); seg.A = element.knots[i].KWorldPos(theT); //START POINT seg.B = element.knots[i].KHandleOutWorldPos(theT); //START TANGENT seg.C = element.knots[i + 1].KHandleInWorldPos(theT); //END TANGENT seg.D = element.knots[i + 1].KWorldPos(theT); //END POINT theSegs.Add(seg); segmentLenghts.Add(GetLengthSimpsons(0f, 1f, seg)); } //Create a list of knot Distances List <float> knotDistances = new List <float>(); float tempDist = 0; knotDistances.Add(tempDist); for (int i = 0; i < segmentLenghts.Count; i++) { tempDist = tempDist + segmentLenghts[i]; knotDistances.Add(tempDist); } //Add the first point curveSteps.Clear(); curveSteps.Add(theSegs[0].A); //For each step for (int i = 1; i < numSteps; i++) { //Get this point dist float distAlong = sectionLength * i; //Find out in wich segment it falls int currSegIndex = 0; for (int f = 0; f < knotDistances.Count - 1; f++) { if (distAlong > knotDistances[f]) { if (distAlong < knotDistances[f + 1]) { currSegIndex = f; } } } //Find out at which distance along that segment the point falls float segPointDist = distAlong - knotDistances[currSegIndex]; //Use Newton–Raphsons method to find the t value from the start of the curve //to the end of the distance we have float t = FindTValue(segPointDist, segmentLenghts[currSegIndex], theSegs[currSegIndex]); //Get the coordinate on the Bezier curve at this t value Vector3 pos = DeCasteljausAlgorithm(t, theSegs[currSegIndex]); //Add the next point to the curveSteps list curveSteps.Add(pos); } return(curveSteps); }
/* RECALCULATE SMOOTH * Algorithm based on : http://www.efg2.com/Lab/Graphics/Jean-YvesQueinecBezierCurves.htm */ void RecalculateSmoothKnot(ShapeElement element, int knotIndex) { //Debug.Log("recalculating index " + knotIndex.ToString()); //Local Variables bool isLast = (knotIndex == element.knots.Length - 1); bool isFirst = (knotIndex == 0); if (!isLast && !isFirst) { //GET THE POINTS TO BE USED Vector3 k0Pos = element.knots[knotIndex - 1].KWorldPos(transform); Vector3 k1Pos = element.knots[knotIndex].KWorldPos(transform); Vector3 k2Pos = element.knots[knotIndex + 1].KWorldPos(transform); //GET THE OFFSETED LINE //Get base Vector Vector3 BaseVec = k0Pos - k2Pos; float baseVecHalfLenght = Vector3.Magnitude(BaseVec) / 2; Vector3 q0 = k1Pos + Vector3.Normalize(BaseVec) * baseVecHalfLenght; Vector3 q1 = k1Pos + Vector3.Normalize(-BaseVec) * baseVecHalfLenght; //GET THE IN TANGENT //GET k2-k1 Vector3 Vector3 k2k1Vec = k2Pos - k1Pos; //Get the smoothed point dist float smoothPoint = k2k1Vec.magnitude / 4; Vector3 pIn0 = k1Pos + Vector3.Normalize(k2k1Vec) * smoothPoint; Vector3 pIn1 = Vector3.Lerp(k0Pos, k1Pos, 0.5f); Vector3 inTangent = SS_Common.GetLineIntersection(q0, q1, pIn0, pIn1); //ASSIGN THE TANGENT element.knots[knotIndex].kHandleIn = inTangent - k1Pos; //GET THE OUT TANGENT Vector3 k0k1Vec = k0Pos - k1Pos; //Get the smoothed point dist smoothPoint = k0k1Vec.magnitude / 4; Vector3 pOut0 = k1Pos + Vector3.Normalize(k0k1Vec) * smoothPoint; Vector3 pOut1 = Vector3.Lerp(k1Pos, k2Pos, 0.5f); Vector3 outTangent = SS_Common.GetLineIntersection(q0, q1, pOut0, pOut1); //ASSIGN THE TANGENT element.knots[knotIndex].kHandleOut = k1Pos - outTangent; } if (isFirst) //We only calculate the OutTangent { Vector3 k0Pos = element.knots[0].KWorldPos(transform); Vector3 k1Pos = element.knots[1].KWorldPos(transform); Vector3 k2Pos = element.knots[2].KWorldPos(transform); //FIRST LINE P //Midpoint of knot[0] , knot[1] = "P0" Vector3 p0 = Vector3.Lerp(k0Pos, k1Pos, 0.5f); //Dir of knot[2] - knot[1] = k2k1Dir Vector3 k2k1Dir = k2Pos - k1Pos; //Half distance between knot[2] - knot[1] = k2k1halfDist float k2k1HalfDist = k2k1Dir.magnitude / 2; //Get Point starting at "P0" traveling "k2k1halfDist" in "k2k1Dir" direction = "P1" Vector3 p1 = p0 + Vector3.Normalize(k2k1Dir) * k2k1HalfDist; //SECOND LINE K //K0 = knot[0] Vector3 q0 = k0Pos; //Get vector from knot[0] to knot[2] = "k0k2Vector" Vector3 k0k2Vector = k2Pos - k0Pos; //Get a quarter of the length of "k0k1Vector" = "smoothLength" float smoothLength = Vector3.Magnitude(k0k2Vector) / 4; //K1 = Starting at P1 travel "smoothLength" along "k0k2Vector" direction Vector3 q1 = p1 + Vector3.Normalize(k0k2Vector) * smoothLength; //GET INTERSECTION Vector3 intersection = SS_Common.GetLineIntersection(p0, p1, q0, q1); element.knots[0].kHandleOut = intersection - k0Pos; } if (isLast) //We only calculate the inTangent { Vector3 k0Pos = element.knots[knotIndex].KWorldPos(transform); Vector3 k1Pos = element.knots[knotIndex - 1].KWorldPos(transform); Vector3 k2Pos = element.knots[knotIndex - 2].KWorldPos(transform); //FIRST LINE P //Midpoint of knot[0] , knot[1] = "P0" Vector3 p0 = Vector3.Lerp(k0Pos, k1Pos, 0.5f); //Dir of knot[2] - knot[1] = k2k1Dir Vector3 k2k1Dir = k2Pos - k1Pos; //Half distance between knot[2] - knot[1] = k2k1halfDist float k2k1HalfDist = k2k1Dir.magnitude / 2; //Get Point starting at "P0" traveling "k2k1halfDist" in "k2k1Dir" direction = "P1" Vector3 p1 = p0 + Vector3.Normalize(k2k1Dir) * k2k1HalfDist; //SECOND LINE K //K0 = knot[0] Vector3 q0 = k0Pos; //Get vector from knot[0] to knot[2] = "k0k2Vector" Vector3 k0k2Vector = k2Pos - k0Pos; //Get a quarter of the length of "k0k1Vector" = "smoothLength" float smoothLength = Vector3.Magnitude(k0k2Vector) / 4; //K1 = Starting at P1 travel "smoothLength" along "k0k2Vector" direction Vector3 q1 = p1 + Vector3.Normalize(k0k2Vector) * smoothLength; //GET INTERSECTION Vector3 intersection = SS_Common.GetLineIntersection(p0, p1, q0, q1); element.knots[knotIndex].kHandleIn = intersection - k0Pos; } }