public override async Task Apply(CADDocument doc, params string[] args) { Editor ed = doc.Editor; ed.PickedSelection.Clear(); var p1 = await ed.GetPoint("Start point: "); if (p1.Result != ResultMode.OK) { return; } var p2 = await ed.GetPoint("End point: ", p1.Value); if (p2.Result != ResultMode.OK) { return; } QuadraticBezier cons = new QuadraticBezier(p1.Value, Point2D.Average(p1.Value, p2.Value), p2.Value); doc.Jigged.Add(cons); var p3 = await ed.GetPoint("Control point: ", (p) => cons.P1 = p); doc.Jigged.Remove(cons); if (p3.Result != ResultMode.OK) { return; } Drawable newItem = new QuadraticBezier(p1.Value, p3.Value, p2.Value); doc.Model.Add(newItem); }
private static void DiscontinuityLocations() { start_discontinuities = new List <QuadraticBezier>(); end_discontinuities = new List <QuadraticBezier>(); for (int index = 0; index < lines.Count; ++index) //for each QuadraticBezier and the next; (including last then first !) { QuadraticBezier QB = lines[index]; if (NearBoundary(QB.begin_UV) && !NearBoundary(QB.end_UV)) // just because this can work does not mean it will always work (at least in theory)... { DebugUtility.Log(QB.begin_UV); end_discontinuities.Add(QB); } else if (NearBoundary(QB.end_UV) && !NearBoundary(QB.begin_UV)) { DebugUtility.Log(QB.end_UV); start_discontinuities.Add(QB); } else if (NearBoundary(QB.begin_UV) && NearBoundary(QB.end_UV) && //TODO: CHECK: include all vertexes unless the line is parallel to the boundary Mathf.Floor(EdgeMapKey(QB.end_UV)) != Mathf.Floor(EdgeMapKey(QB.begin_UV))) { DebugUtility.Log(QB.end_UV); DebugUtility.Log(QB.begin_UV); end_discontinuities.Add(QB); start_discontinuities.Add(QB); } } }
public override void OnInspectorGUI() { QuadraticBezier thisBezier = (QuadraticBezier)target; base.OnInspectorGUI(); EditorGUILayout.LabelField("Bezier Length", thisBezier.bezierLength.ToString()); EditorGUILayout.Space(); if (GUILayout.Button("Center Bezier Between End Points")) { thisBezier.CenterBezierPoint(); } EditorGUILayout.Space(); if (GUILayout.Button("Create Right Angle Bezier[1]")) { thisBezier.RightAngleBezierPoint1(); } if (GUILayout.Button("Create Right Angle Bezier[2]")) { thisBezier.RightAngleBezierPoint2(); } if (GUILayout.Button("Calculate Bezier Length")) { ; } }
private static void BuildShape() { //each "shape" may contain more than one shape (e.g. a zig-zag on the southern hemisphere between two octahedral faces will have #zig + #zag + 1 shapes) edge_pattern = new Dictionary <QuadraticBezier, QuadraticBezier>(); BuildDictionary(); DiscontinuityLocations(); AugmentDictionary(); // add edges that are along the square (0,0) -> (1,0) -> (1,1) -> (0,1) while (edge_pattern.Count != 0) // make sure there are no more shapes left to process { Dictionary <QuadraticBezier, QuadraticBezier> .Enumerator iter = edge_pattern.GetEnumerator(); iter.MoveNext(); QuadraticBezier first_edge = iter.Current.Key; QuadraticBezier current_edge = first_edge; SVGBuilder.BeginShape(); do // process every edge in each shape { SVGBuilder.SetEdge(current_edge); QuadraticBezier temp_edge = current_edge; DebugUtility.Log("Cycling:", current_edge.end_UV, current_edge.begin_UV); current_edge = edge_pattern[current_edge]; edge_pattern.Remove(temp_edge); } while (current_edge != first_edge); SVGBuilder.EndShape(); } }
public static void SetEdge(QuadraticBezier curve) { if (first) { writer.Write("M" + curve.begin_UV.x * 1000 + "," + curve.begin_UV.y * 1000); first = false; } writer.Write(" Q" + curve.control_point.x * 1000 + "," + curve.control_point.y * 1000 + " " + curve.end_UV.x * 1000 + "," + curve.end_UV.y * 1000); }
public void Reset() { EditorOnlyToolSettings = new ToolSettings(); var localBezier = new QuadraticBezier( new Vector3(0.5f, 0f, 0f), new Vector3(0f, 0.5f, 0.5f), new Vector3(0.5f, 1.0f, 0.5f) ); Path = new QuadraticBezierPath(transform, localBezier); }
private static void OverlapSharedEdges() { for (int index = 0; index < lines.Count; ++index) //for each QuadraticBezier and the next; (including last then first !) { QuadraticBezier QB1 = lines[index]; QuadraticBezier QB2 = lines[(index + 1) % lines.Count]; if (Vector2.Distance(QB1.end_UV, QB2.begin_UV) < threshold) //if QB1.end ~= QB2.begin { QB1.end = QB2.begin = (QB1.end + QB2.begin) / 2; //make the points equal } } }
private static void BuildDictionary() { for (int index = 0; index < lines.Count; ++index) //for each QuadraticBezier and the next; (including last then first !) { QuadraticBezier QB1 = lines[index]; QuadraticBezier QB2 = lines[(index + 1) % lines.Count]; if (!NearBoundary(QB1.end_UV) && !NearBoundary(QB2.begin_UV)) // take identical points and link them { edge_pattern.Add(QB1, QB2); //should work since it's referencing the QuadraticBezier inside of the List<QB> } } }
private static void ClampToEdges() { for (int index = 0; index < lines.Count; ++index) //for each QuadraticBezier and the next; (including last then first !) { QuadraticBezier QB1 = lines[index]; QuadraticBezier QB2 = lines[(index + 1) % lines.Count]; if (NearBoundary(QB1.end_UV)) //if end is not close to begin, there is a discontinuity { ProjectOntoSquare(ref QB1.end_UV, QB1.control_point); // project the points onto the edge of a square ProjectOntoSquare(ref QB2.begin_UV, QB2.control_point); } } }
protected override List <PointF> GetPoints() { QuadraticBezier qb = new QuadraticBezier(); qb.StartPoint = Start; qb.EndPoint = End; qb.Control = control; qb.Resolution = 100; qb.CalculatePoints(); List <PointF> pts = new List <PointF>(); pts.AddRange(qb.Points); return(pts); }
/// <summary> /// Returns the world position of "t" percentage along a given bezier. /// </summary> /// <param name="checkedBezier"></param> /// <param name="percentageAlongBezier"></param> /// <returns></returns> public static Vector3 GetPositionFromCompletionPercentage(this QuadraticBezier main, float t) { Vector3 p0 = main.points[0]; Vector3 p1 = main.points[1]; Vector3 p2 = main.points[2]; if (t < 0) { return(p1); } else if (t > 1) { return(p2); } else { Vector3 bezierCalc = p1 + (Mathf.Pow(1 - t, 2) * (p0 - p1)) + (Mathf.Pow(t, 2) * (p2 - p1)); return(bezierCalc); } }
private void Draw() { QuadraticBezier worldBezier = qdrBezierPath.WorldSpaceBezier; var cPointCache = new EvaluationCache(worldBezier, QuadraticBezier.GoodNumMidPoints).Values; // draw bezier PathEditorUtility.DrawSplineInScene(cPointCache); // draw direction cone cap if (!settings.HideDirectionCones && targetScript.transform.lossyScale != Vector3.zero) // also hide cones if virtually a dot { float startConeSize = PathEditorUtility.Nice3DHandleSize(worldBezier.Evaluate(0f)); float endConeSize = PathEditorUtility.Nice3DHandleSize(worldBezier.Evaluate(1f)); Handles.color = Color.yellow; Handles.ConeCap(0, worldBezier.Evaluate(0f), Quaternion.LookRotation(worldBezier.Evaluate(0.01f) - worldBezier.Evaluate(0f)), startConeSize); Handles.color = Color.magenta; Handles.ConeCap(0, worldBezier.Evaluate(1f), Quaternion.LookRotation(worldBezier.Evaluate(1f) - worldBezier.Evaluate(1f - 0.01f)), endConeSize); } // draw tangent lines if (!settings.HideTangentLines) { Handles.color = Color.cyan; Handles.DrawDottedLine(worldBezier.StartPosition, worldBezier.MidTangent, 7.5f); Handles.DrawDottedLine(worldBezier.MidTangent, worldBezier.EndPosition, 7.5f); } // test t if (settings.TestInterpolate) { PathEditorUtility.DrawTestInterpolate(worldBezier, settings.EditorData.T); } // draw GUI InterpolateSceneGUI(); ToolShelf(); }
private static void StitchTogether(QuadraticBezier cursor, QuadraticBezier last) { if (swapped) { QuadraticBezier swapper = cursor; cursor = last; last = swapper; } DebugUtility.Log("Stitching:", cursor.end_UV, last.begin_UV); float cursor_key = EdgeMapKey(cursor.end_UV); float last_key = EdgeMapKey(last.begin_UV); bool clockwise = Vector3.Dot(ClockwiseDirection(cursor_key), -cursor.arc.EvaluateRight(cursor.end)) > 0; // left for start_edge_map/end because right DNE // add edges that weren't added by BuildDictionary (along the square (0,0) -> (1,0) -> (1,1) -> (0,1) ) optional <Vector2> corner = NextCorner(cursor_key, last_key, clockwise); Vector2 control_point; QuadraticBezier intermediate_line; while (corner.exists) { Debug.Log(corner); control_point = (cursor.end_UV + corner.data) / 2; intermediate_line = new QuadraticBezier(null, cursor.end_UV, control_point, corner.data, -1f, -1f); edge_pattern.Add(cursor, intermediate_line); cursor = intermediate_line; cursor_key = EdgeMapKey(cursor.end_UV); corner = NextCorner(cursor_key, last_key, clockwise); } control_point = (cursor.end_UV + last.begin_UV) / 2; intermediate_line = new QuadraticBezier(null, cursor.end_UV, control_point, last.begin_UV, -1f, -1f); edge_pattern.Add(cursor, intermediate_line); edge_pattern.Add(intermediate_line, last); }
static void Main(string[] args) { // Create the window and the graphics device VeldridInit(out var window, out var graphicsDevice); // Create a texture storage that manages textures. // Textures in OpenWheels are represented with integer values. // A platform-specific ITextureStorageImplementation handles texture creation, // destruction and modification. var texStorage = new VeldridTextureStorage(graphicsDevice); // Create a renderer that implements the OpenWheels.Rendering.IRenderer interface // this guy actually draws everything to the backbuffer var renderer = new VeldridRenderer(graphicsDevice, texStorage); // OpenWheels always requires a texture to render, so renderer implementations only need a single shader // Even for untextured primitives we need to have a texture set. So we create a white 1x1 texture for those. ReadOnlySpan <Color> blankSpan = stackalloc Color[] { Color.White }; var blank = texStorage.CreateTexture(1, 1, TextureFormat.Rgba32); texStorage.SetData(blank, blankSpan); // Our batcher lets use make calls to render lots of different primitive shapes and text. // When we're done the batcher can export draw calls so the renderer can use them do the drawing. // We won't use text rendering in this sample so we use the dummy text renderer. var batcher = new Batcher(NullBitmapFontRenderer.Instance); var first = true; // We run the game loop here and do our drawing inside of it. VeldridRunLoop(window, graphicsDevice, () => { renderer.Clear(Color.CornflowerBlue); // Start a new batch batcher.Start(); // set the texture to the blank one we registered batcher.SetTexture(blank); // Let's draw some primitives. The API is very obvious, you can use IntelliSense to find supported shapes. batcher.FillRect(new RectangleF(10, 10, 100, 100), Color.LimeGreen); // Note that subsequent line segments are connected at their corners Span <Vector2> points = stackalloc Vector2[] { new Vector2(140, 20), new Vector2(320, 20), new Vector2(320, 120), new Vector2(420, 120) }; batcher.DrawLineStrip(points, Color.Red, 20); batcher.FillTriangle(new Vector2(500, 20), new Vector2(600, 70), new Vector2(500, 120), Color.White); // The tessellation of the circle and corners for the rounded rectangle can be adjusted with the maxError parameter batcher.DrawCircle(new Vector2(700, 70), 50, Color.BlueViolet, 2); batcher.FillRoundedRect(new RectangleF(790, 10, 100, 100), 10, Color.SandyBrown); var pa = new Vector2(50, 220); var pb = new Vector2(150, 120); var pc = new Vector2(250, 220); var curve = new QuadraticBezier(pa, pb, pc); // The segmentation for curves can be adjusted with the segmentsPerLength parameter // Using that parameter and an (over)estimate of the length of the curve the number of segments // is computed batcher.DrawCurve(curve, Color.DarkGoldenrod, 2); var o = new Vector2(0, 100); var pd = new Vector2(200, 420); var curve2 = new CubicBezier(pa + o, pb + o, pd, pc + o); batcher.DrawCurve(curve2, Color.DarkOrchid, 2); // Finish the batch and let the renderer draw everything to the back buffer. batcher.Render(renderer); if (first) { Console.WriteLine("Vertices: " + batcher.VerticesSubmitted); Console.WriteLine("Indices: " + batcher.IndicesSubmitted); Console.WriteLine("Batches: " + batcher.BatchCount); first = false; } });
IEnumerator FollowRoute(Transform route) { CheckForRigidbody(); //Starts Route, creates the points p0 (Start Pos) p1 (Bezier Pos) and p2 (End Pos) enRoute = true; QuadraticBezier currentBezier = currentRoute.gameObject.GetComponent <QuadraticBezier>(); Vector3 initialPos = currentBezier.points[0]; bezLength = currentBezier.bezierLength; if (Mathf.Abs((transform.position - initialPos).magnitude) > 2) { while (Mathf.Abs((transform.position - initialPos).magnitude) > .1f) { rb.transform.position = Vector3.Lerp(transform.position, initialPos, changePathSpeed * Time.deltaTime); yield return(new WaitForEndOfFrame()); } } QuadraticBezier nextRoute = NearestBezier(currentBezier.points[2]).GetComponent <QuadraticBezier>(); bool overrideStopping = false; if (currentBezier.isStoplightNode) { if (currentBezier.isTurn()) { inTurn = true; } else { inTurn = false; } } else { inTurn = false; } float t = 0; bool hasHonked = false; while (t < 1) { if (!overrideStopping) { if ((transform.position - nextRoute.points[0]).magnitude < 5 && nextRoute.isStoplightNode) { while (nextRoute.stopLightOrder != StoplightManager.currentLight && StoplightManager.currentLight != 0 && !currentBezier.isStoplightNode) { canRotate = false; yield return(new WaitForEndOfFrame()); } while (StoplightManager.currentLight == 0) { yield return(new WaitForEndOfFrame()); } } if (currentBezier.isStoplightNode && StoplightManager.currentLight != currentBezier.stopLightOrder && StoplightManager.currentLight != 0) { if (currentBezier.isTurn() && (transform.position - PlayerManager.position).magnitude > 40) { overrideStopping = true; collider.enabled = false; } } } if (!SenseObjects()) { canRotate = true; t += Time.deltaTime / bezLength * speed; //Move along any length of bezier at consistent speed } else { if (!hasHonked) //If the car has not honked on its current route and a player is in front of it, then there is a 40% chance it will honk its horn { if (SensePlayer()) { hasHonked = true; SoundEffectManager.Instance.CarHonk(); } } if (overrideStopping) { canRotate = true; t += Time.deltaTime / bezLength * speed; //Move along any length of bezier at consistent speed } else { canRotate = false; } } playerPos = currentBezier.GetPositionFromCompletionPercentage(t); rb.transform.position = playerPos; yield return(new WaitForEndOfFrame()); } collider.enabled = true; enRoute = false; yield return(null); }