/// <summary> /// Unity inspector function. /// </summary> public override void OnInspectorGUI() { if (drawKnots == false) { this.selectedNodes.Clear(); } base.OnInspectorGUI(); drawKnots = EditorGUILayout.Toggle("Draw Knots", drawKnots); BernyTest t = (BernyTest)this.target; if (t == null || t.curveDocument == null) { return; } this.showCurveIDs = GUILayout.Toggle(this.showCurveIDs, "Show Curve IDs"); if (GUILayout.Button("Test Validity") == true) { t.curveDocument.TestValidity(); } if (GUILayout.Button("Fill") == true) { t.UpdateFillsForAll(BernyTest.FillType.Filled, this.strokeWidth); } if (GUILayout.Button("Fill Outline") == true) { t.UpdateFillsForAll(BernyTest.FillType.Outlined, this.strokeWidth); } if (GUILayout.Button("Fill Outlined") == true) { t.UpdateFillsForAll(BernyTest.FillType.FilledAndOutlined, this.strokeWidth); } this.strokeWidth = EditorGUILayout.Slider("Stroke Width", this.strokeWidth, 0.001f, 1.0f); GUILayout.BeginHorizontal(); GUI.color = Color.green; if (GUILayout.Button("Select All") == true) { this.selectedNodes = new HashSet <BNode>(t.curveDocument.EnumerateNodes()); } GUI.color = Color.white; if (GUILayout.Button("Deselect All") == true) { this.selectedNodes.Clear(); } GUILayout.EndHorizontal(); if (GUILayout.Button("Scan Selected Intersections") == true) { this.ScanSelectedIntersections(t.curveDocument); } GUILayout.Space(20.0f); string [] files = new string[] { "Ven", "TriVen", "CircAnCirc", "Complex", "Complex2", "Edges", "ShapeCircle", "ShapeEllipse", "ShapeLine", "ShapePolygon", "ShapePolyline", "ShapeRect" }; foreach (string f in files) { GUILayout.BeginHorizontal(); if (GUILayout.Button("LOAD " + f) == true) { t.curveDocument.Clear(); SVGSerializer.Load("TestSamples/" + f + ".svg", t.curveDocument, true); t.curveDocument.FlushDirty(); } if (GUILayout.Button("...", GUILayout.Width(30.0f)) == true) { System.Diagnostics.Process.Start("TestSamples\\" + f + ".svg"); } GUILayout.EndHorizontal(); } GUILayout.Space(20.0f); this.infAmt = EditorGUILayout.FloatField("Inflation Amt", this.infAmt); if (GUILayout.Button("Inflate") == true) { foreach (Layer l in t.curveDocument.Layers()) { foreach (BShape bs in l.shapes) { foreach (BLoop bl in bs.loops) { bl.Deinflect(); bl.Inflate(this.infAmt); } } } } if (GUILayout.Button("Edgeify") == true) { foreach (BLoop bl in t.curveDocument.EnumerateLoops()) { bl.Deinflect(); PxPre.Berny.Operators.Edgify(bl, this.infAmt); } } GUILayout.Space(20.0f); GUI.color = Color.red; if (GUILayout.Button("Clear") == true) { t.curveDocument.Clear(); t.ClearFills(); } GUI.color = Color.white; if (GUILayout.Button("Save SVG") == true) { SVGSerializer.Save("TestSave.svg", t.curveDocument); } if (GUILayout.Button("Load SVG") == true) { t.curveDocument.Clear(); SVGSerializer.Load("TestSave.svg", t.curveDocument); } GUILayout.Space(20.0f); if (this.selectedNodes.Count > 0) { if (GUILayout.Button("Reverse Windings") == true) { HashSet <BLoop> loops = new HashSet <BLoop>(); foreach (BNode bn in this.selectedNodes) { loops.Add(bn.parent); } foreach (BLoop loop in loops) { if (loop == null) { continue; } loop.Reverse(); } } GUI.color = Color.red; GUILayout.BeginHorizontal(); if (GUILayout.Button("Delete Selected") == true) { foreach (BNode selNode in this.selectedNodes) { selNode.parent.RemoveNode(selNode); } this.selectedNodes.Clear(); this.movedTangent = null; } if (GUILayout.Button("Disconnect Selected") == true) { foreach (BNode selNode in this.selectedNodes) { selNode.Disconnect(true); } } if (GUILayout.Button("Detach Selected") == true) { foreach (BNode selNode in this.selectedNodes) { selNode.Detach(); } } GUILayout.EndHorizontal(); GUI.color = Color.white; if (GUILayout.Button("Expand Islands") == true) { HashSet <BNode> toScan = new HashSet <BNode>(this.selectedNodes); while (toScan.Count > 0) { BNode bnCut = Utils.GetFirstInHash(toScan); foreach (BNode bnT in bnCut.Travel()) { toScan.Remove(bnT); this.selectedNodes.Add(bnT); } } } if (GUILayout.Button("Connect") == true) { if (this.selectedNodes.Count != 2) { return; } List <BNode> selList = new List <BNode>(this.selectedNodes); selList[0].parent.ConnectNodes(selList[0], selList[1]); } if (GUILayout.Button("Subdivide Selected") == true) { HashSet <BNode> subbed = new HashSet <BNode>(); foreach (BNode selNode in this.selectedNodes) { BNode bsubed = selNode.Subdivide(0.5f); if (bsubed != null) { subbed.Add(bsubed); } } if (subbed.Count > 0) { foreach (BNode bn in subbed) { this.selectedNodes.Add(bn); } this.RecalculateSelectionCentroid(); } } GUILayout.BeginHorizontal(); if (GUILayout.Button("Round Selected") == true) { foreach (BNode selNode in this.selectedNodes) { selNode.Round(); } } if (GUILayout.Button("Smooth") == true) { foreach (BNode selNode in this.selectedNodes) { selNode.SetTangentSmooth(); } } if (GUILayout.Button("Symmetrize") == true) { foreach (BNode selNode in this.selectedNodes) { selNode.SetTangentsSymmetry(); } } if (GUILayout.Button("Disconnect") == true) { foreach (BNode selNode in this.selectedNodes) { selNode.SetTangentDisconnected(); } } GUILayout.EndHorizontal(); GUILayout.BeginHorizontal(); if (GUILayout.Button("Enable Inputs") == true) { foreach (BNode selNode in this.selectedNodes) { selNode.UseTanIn = true; } } if (GUILayout.Button("Enable Outputs") == true) { foreach (BNode selNode in this.selectedNodes) { selNode.UseTanOut = true; } } GUILayout.EndHorizontal(); GUILayout.BeginHorizontal(); if (GUILayout.Button("Disable Inputs") == true) { foreach (BNode selNode in this.selectedNodes) { selNode.UseTanIn = false; } } if (GUILayout.Button("Disable Outputs") == true) { foreach (BNode selNode in this.selectedNodes) { selNode.UseTanOut = false; } } GUILayout.EndHorizontal(); if (GUILayout.Button("Islands") == true) { HashSet <BLoop> foundLoops = new HashSet <BLoop>(); foreach (BNode bn in this.selectedNodes) { foundLoops.Add(bn.parent); } foreach (BLoop bl in foundLoops) { int island = bl.CalculateIslands(); for (int i = 0; i < island - 1; ++i) { bl.ExtractIsland(bl.nodes[0]); } } } GUILayout.BeginHorizontal(); if (GUILayout.Button("Winding Simple") == true) { if (this.selectedNodes.Count > 0) { BNode bn = Utils.GetFirstInHash(this.selectedNodes); float w = bn.parent.CalculateWindingSimple(bn, true); Debug.Log("Simple winding of " + w.ToString()); } } if (GUILayout.Button("Winding Samples") == true) { BNode bn = Utils.GetFirstInHash(this.selectedNodes); float w = bn.parent.CalculateWindingSamples(bn, true); Debug.Log("Simple winding of " + w.ToString()); } GUILayout.EndHorizontal(); GUILayout.BeginHorizontal(); if (GUILayout.Button("Calculate ArcLength") == true) { HashSet <BLoop> loops = new HashSet <BLoop>(); foreach (BNode bn in this.selectedNodes) { loops.Add(bn.parent); } foreach (BLoop loop in loops) { float len = loop.CalculateArclen(); Debug.Log("Calculated arclen of " + len.ToString()); } } if (GUILayout.Button("Calculate SampleLen") == true) { HashSet <BLoop> loops = new HashSet <BLoop>(); foreach (BNode bn in this.selectedNodes) { loops.Add(bn.parent); } foreach (BLoop loop in loops) { float len = loop.CalculateSampleLens(); Debug.Log("Calculated sample len of " + len.ToString()); } } GUILayout.EndHorizontal(); if (GUILayout.Button("Calculate BBoxes") == true) { BoundsMM2 total = BoundsMM2.GetInifiniteRegion(); foreach (BNode bn in this.selectedNodes) { if (bn.next == null) { continue; } BoundsMM2 b2 = bn.GetBounds(); Debug.Log($"Node found to have bounds of region min {{{b2.min.x}, {b2.min.y}}} - and max {{{b2.max.x}, {b2.max.y} }}"); total.Union(b2); } Debug.Log($"Total selected bounds of region min {{{total.min.x}, {total.min.y}}} - and max {{{total.max.x}, {total.max.y} }}"); } if (GUILayout.Button("Split into Thirds") == true) { Vector2 pt0, pt1, pt2, pt3; foreach (BNode bn in this.selectedNodes) { if (bn.next == null) { continue; } Utils.SubdivideBezier(bn.Pos, bn.Pos + bn.TanOut, bn.next.Pos + bn.next.TanIn, bn.next.Pos, out pt0, out pt1, out pt2, out pt3, 0.1f, 0.9f); bn.Pos = pt0; bn.TanOut = (pt1 - pt0); bn.next.TanIn = (pt2 - pt3); bn.next.Pos = pt3; } } GUILayout.Space(20.0f); this.intersectTestStart = EditorGUILayout.Vector2Field("Intersection Start", this.intersectTestStart); this.intersectTextEnd = EditorGUILayout.Vector2Field("Intersection End", this.intersectTextEnd); if (GUILayout.Button("Line Intersection Test") == true) { this.intersectionPreviews.Clear(); foreach (BNode node in this.selectedNodes) { List <float> curveOuts = new List <float>(); if (node.next == null) { continue; } BNode.PathBridge pb = node.GetPathBridgeInfo(); Vector2 pt0 = node.Pos; Vector2 pt1 = node.Pos + pb.prevTanOut; Vector2 pt2 = node.next.Pos + pb.nextTanIn; Vector2 pt3 = node.next.Pos; int cols = Utils.IntersectLine( curveOuts, null, pt0, pt1, pt2, pt3, this.intersectTestStart, this.intersectTextEnd); for (int i = 0; i < cols; ++i) { float intLam = curveOuts[i]; float a, b, c, d; Utils.GetBezierWeights(intLam, out a, out b, out c, out d); this.intersectionPreviews.Add(a * pt0 + b * pt1 + c * pt2 + d * pt3); } } if (this.intersectionPreviews.Count == 0) { Debug.Log("No collisions found"); } else { Debug.Log($"{this.intersectionPreviews.Count} Collisions found"); } } GUILayout.BeginHorizontal(); if (GUILayout.Button("Wind Sel Back") == true) { List <BNode> bnsel = new List <BNode>(this.selectedNodes); this.selectedNodes.Clear(); foreach (BNode bn in bnsel) { if (bn.prev != null) { this.selectedNodes.Add(bn.prev); } } } if (GUILayout.Button("Wind Sel Fwd") == true) { List <BNode> bnsel = new List <BNode>(this.selectedNodes); this.selectedNodes.Clear(); foreach (BNode bn in bnsel) { if (bn.next != null) { this.selectedNodes.Add(bn.next); } } } GUILayout.EndHorizontal(); GUILayout.BeginHorizontal(); if (GUILayout.Button("Test Union") == true) { BLoop srcLoop = null; List <BLoop> loops = Boolean.GetUniqueLoopsInEncounteredOrder(out srcLoop, this.selectedNodes); // If loops is filled, srcLoop should be non-null if (loops.Count > 0) { BNode filler; Boolean.Union(srcLoop, out filler, loops.ToArray()); } } if (GUILayout.Button("Union Trace") == true) { List <BLoop> loops = Boolean.GetUniqueLoopsInEncounteredOrder(this.selectedNodes); Boolean.TraceUnion(loops, loops[0], null, true); } GUILayout.EndHorizontal(); GUILayout.BeginHorizontal(); if (GUILayout.Button("Test Difference") == true) { List <BLoop> loops = Boolean.GetUniqueLoopsInEncounteredOrder(this.selectedNodes); if (loops.Count >= 2) { BNode filler; Boolean.Difference(loops[0], loops[1], out filler); } } if (GUILayout.Button("Difference Trace") == true) { List <BLoop> loops = Boolean.GetUniqueLoopsInEncounteredOrder(this.selectedNodes); if (loops.Count >= 2) { Boolean.TraceDifference( loops[0], loops[1], loops[0], true); } } GUILayout.EndHorizontal(); GUILayout.BeginHorizontal(); if (GUILayout.Button("Test Intersection") == true) { List <BLoop> loops = Boolean.GetUniqueLoopsInEncounteredOrder(this.selectedNodes); if (loops.Count >= 2) { BNode filler; Boolean.Intersection(loops[0], loops[1], out filler, true); } } if (GUILayout.Button("Intersection Trace") == true) { List <BLoop> loops = Boolean.GetUniqueLoopsInEncounteredOrder(this.selectedNodes); if (loops.Count >= 2) { Boolean.TraceIntersection( loops[0], loops[1], loops[0], null, true); } } GUILayout.EndHorizontal(); if (GUILayout.Button("Test Exclusion") == true) { List <BLoop> loops = Boolean.GetUniqueLoopsInEncounteredOrder(this.selectedNodes); if (loops.Count >= 2) { Boolean.Exclusion(loops[0], loops[1], true); } } if (GUILayout.Button("Bridge") == true) { HashSet <BLoop> loops = new HashSet <BLoop>(); List <BLoop> ol = new List <BLoop>(); foreach (BNode bn in this.selectedNodes) { if (loops.Add(bn.parent) == true) { ol.Add(bn.parent); } } if (ol.Count > 0) { BLoop blTarg = ol[0]; if (ol.Count >= 2) { //Boolean.Union(blTarg, ol[1]); ol[1].DumpInto(blTarg); } List <BNode> islands = blTarg.GetIslands(IslandTypeRequest.Closed); if (islands.Count >= 2) { List <BNode> segmentsA = new List <BNode>(islands[0].Travel()); List <BNode> segmentsB = new List <BNode>(islands[1].Travel()); BNode innerBridgeSeg, outerBridgeSeg; float innerBridgeT, outerBridgeT; BNode.FindBridge( segmentsA, segmentsB, out innerBridgeSeg, out outerBridgeSeg, out innerBridgeT, out outerBridgeT); if (outerBridgeSeg != null) { // We have what we need for a connection. BNode.MakeBridge(innerBridgeSeg, innerBridgeT, outerBridgeSeg, outerBridgeT); } } } } } textToCreate = GUILayout.TextField( textToCreate, GUILayout.ExpandWidth(true), GUILayout.Height(100.0f)); bridgeFonts = GUILayout.Toggle(bridgeFonts, "Bridge Font"); if (GUILayout.Button("Create Text") == true) { List <BShape> charShapes = PxPre.Berny.Text.GenerateString( t.curveDocument.GetFirstLayer(), Vector2.zero, t.typeface, 1.0f, textToCreate); if (bridgeFonts == true) { foreach (BShape bs in charShapes) { Text.BridgeGlyph(bs); } } } if (GUILayout.Button("Bridge Font Shapes") == true) { foreach (BShape shape in t.curveDocument.EnumerateShapes()) { Text.BridgeGlyph(shape); } } if (GUILayout.Button("Clean") == true) { t.curveDocument.Clean(); } if (t.curveDocument.IsDirty() == true) { t.curveDocument.FlushDirty(); } }