Beispiel #1
0
    /// <summary>
    /// Render the tree data of the document, and render the outline and preview to the Scene view.
    /// </summary>
    private void OnSceneGUI()
    {
        BernyTest t = (BernyTest)this.target;

        if (t == null || t.curveDocument == null)
        {
            return;
        }

        Handles.BeginGUI();
        foreach (BNode selbn in this.selectedNodes)
        {
#if DEVELOPMENT_BUILD || UNITY_EDITOR
            int parentID = (selbn.parent != null) ? selbn.parent.debugCounter : -1;
            GUILayout.Label($"Selected: {selbn.debugCounter.ToString()} - {selbn.tangentMode.ToString()} - {selbn.Pos.x} : {selbn.Pos.y} - [Parent: {parentID}]");
#else
            GUILayout.Label($"Selected: {selbn.tangentMode.ToSTring()} - {selbn.Pos.x} : {selbn.Pos.y}");
#endif
        }

        this.DoUIDocument(t.curveDocument, 0.0f);

        if (this.showCurveIDs == true && Camera.current != null)
        {
            foreach (BNode bn in t.curveDocument.EnumerateNodes())
            {
                Vector2 v2 = Camera.current.WorldToScreenPoint(bn.Pos);
                GUI.Label(new Rect(v2.x + 10.0f, Screen.height - v2.y - 90, 100.0f, 100.0f), bn.debugCounter.ToString());
            }
        }

        Handles.EndGUI();



        bool recalculateAverage = false;

        for (int i = 0; i < this.intersectionPreviews.Count; ++i)
        {
            Handles.Button(
                this.intersectionPreviews[i],
                Quaternion.identity,
                0.1f,
                0.1f,
                Handles.SphereHandleCap);
        }
        //Handles.DrawLine(this.intersectTestStart, this.intersectTextEnd);

        // Draw all curves and show handles for them.
        Handles.color = Color.white;
        foreach (BNode bn in t.curveDocument.EnumerateNodes())
        {
            bool sel = this.selectedNodes.Contains(bn);
            if (sel == true)
            {
                Handles.color = Color.green;
            }
            else
            {
                Handles.color = Color.white;
            }

            if (drawKnots == true)
            {
                bool inter = Handles.Button(bn.Pos, Quaternion.identity, 0.02f, 0.02f, Handles.CubeHandleCap);

                Handles.color = Color.white;
                if (inter == true)
                {
                    recalculateAverage = true;

                    if (Event.current.shift == true)
                    {
                        if (sel == true)
                        {
                            this.selectedNodes.Remove(bn);
                        }
                        else
                        {
                            this.selectedNodes.Add(bn);
                        }
                    }
                    else
                    {
                        this.selectedNodes.Clear();
                        this.selectedNodes.Add(bn);
                    }

                    this.movedTangent = null;
                }
            }

            BSample bit      = bn.sample;
            BSample bitFirst = bit;
            while (bit != null && bit.parent == bn && bit.next != null)
            {
                Handles.DrawLine(bit.pos, bit.next.pos);
                bit = bit.next;

                if (bit == bitFirst)
                {
                    break;
                }
            }

            if (this.showCurveIDs == true && bn.next != null)
            {
                Vector2 tan = bn.GetTangent(BNode.TangentType.Input);
                if (tan.sqrMagnitude < Mathf.Epsilon)
                {
                    continue;
                }

                float ang = Mathf.Atan2(tan.y, tan.x);

                float   angS1 = ang - 0.2f;
                Vector2 vang1 = new Vector2(Mathf.Cos(angS1), Mathf.Sin(angS1)) * 0.3f;
                float   angS2 = ang + 0.2f;
                Vector2 vang2 = new Vector2(Mathf.Cos(angS2), Mathf.Sin(angS2)) * 0.3f;

                Handles.DrawLine(bn.Pos, bn.Pos + vang1);
                Handles.DrawLine(bn.Pos, bn.Pos + vang2);
            }
        }

        // For selected items, show handles for their tangents.
        if (drawKnots == true)
        {
            foreach (BNode bn in this.selectedNodes)
            {
                if (bn.UseTanIn == true)
                {
                    Handles.color = Color.blue;
                    if (Handles.Button(bn.Pos + bn.TanIn, Quaternion.identity, 0.01f, 0.01f, Handles.CubeHandleCap) == true)
                    {
                        this.movedTangent     = bn;
                        this.movedTangentType = BNode.TangentType.Input;
                    }
                    Handles.color = Color.white;
                    Handles.DrawDottedLine(bn.Pos + bn.TanIn, bn.Pos, 1.0f);
                }

                //
                if (bn.UseTanOut == true)
                {
                    Handles.color = Color.blue;
                    if (Handles.Button(bn.Pos + bn.TanOut, Quaternion.identity, 0.01f, 0.01f, Handles.CubeHandleCap) == true)
                    {
                        this.movedTangent     = bn;
                        this.movedTangentType = BNode.TangentType.Output;
                    }
                    Handles.color = Color.white;
                    Handles.DrawDottedLine(bn.Pos + bn.TanOut, bn.Pos, 1.0f);
                }
            }
        }

        if (this.movedTangent != null)
        {
            Vector3 oriPos =
                (this.movedTangentType == BNode.TangentType.Input) ?
                this.movedTangent.TanIn :
                this.movedTangent.TanOut;

            oriPos += (Vector3)this.movedTangent.Pos;

            Vector3 tanPos = Handles.PositionHandle(oriPos, Quaternion.identity);

            if (tanPos != oriPos)
            {
                Vector2 newTan = (Vector2)tanPos - this.movedTangent.Pos;
                if (this.movedTangentType == BNode.TangentType.Input)
                {
                    this.movedTangent.TanIn = newTan;
                }
                else
                {
                    this.movedTangent.TanOut = newTan;
                }

                this.movedTangent.FlagDirty();
            }
        }

        if (recalculateAverage == true)
        {
            this.RecalculateSelectionCentroid();
        }

        if (this.selectedNodes.Count > 0)
        {
            Vector3 origAvg = this.averagePoint;
            Vector3 mod     = Handles.PositionHandle(origAvg, Quaternion.identity);

            if (origAvg != mod)
            {
                Vector2 diff = mod - origAvg;
                this.averagePoint = mod;

                foreach (BNode bn in this.selectedNodes)
                {
                    bn.Pos += diff;
                    bn.FlagDirty();
                }
            }
        }

        if (t.curveDocument.IsDirty() == true)
        {
            t.curveDocument.FlushDirty();
        }
    }
Beispiel #2
0
    /// <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();
        }
    }