Example #1
0
        /// <summary>
        /// draws a list of 2D curves. See also <see cref="CurveArray"/>
        /// </summary>
        /// <param name="CA"><see cref="CurveArray"/></param>
        public void drawPolyCurve(CurveArray CA)
        {
            xyArray A      = CA.getxyArray();
            Object  Handle = null;

            if ((RenderKind == RenderKind.SnapBuffer))
            {
                Handle = Selector.RegisterSnapItem(new PolyCurveSnappItem(CA));
            }
            drawPolyLine(A);
            if ((RenderKind == RenderKind.SnapBuffer))
            {
                Selector.UnRegisterSnapItem(Handle);
            }
        }
Example #2
0
        /// <summary>
        /// refreshes the <see cref="Edge.ParamCurve"/> of the <see cref="EdgeList"/>.
        /// <see cref="ParamCurves"/>-liste. Diese doppelte Verwaltung der ParamCurves wird lediglich aus Performancegründen gemacht.
        /// </summary>
        public virtual void RefreshParamCurves()
        {
            Solid P = Parent;

            DrawPoints       = new Loxyz();
            DrawPoints.Count = Bounds.Count;

            if (ParamCurves == null)
            {
                Surface.BoundedCurves = new Loca();
            }
            ParamCurves.Clear();
            for (int i = 0; i < Bounds.Count; i++)
            {
                EdgeLoop   EL = Bounds[i];
                CurveArray CA = new CurveArray();
                ParamCurves.Add(CA);
                for (int j = 0; j < EL.Count; j++)
                {
                    Edge E = EL[j];
                    if (!DrawRelativToSurfaceBase)
                    {
                        DrawPoints[i].Add(E.EdgeStart.Value);
                    }
                    Curve c = Surface.To2dCurve(EL[j].EdgeCurve);
                    if (!EL[j].SameSense)
                    {
                        c.Invert();
                    }
                    EL[j].ParamCurve = c;

                    CA.Add(c);
                }
                xyArray A = CA.getxyArrayClosed(false);

                DrawPoints[i] = A.ToxyzArray();
            }
        }
Example #3
0
        private ArrayList GetConnections()
        {
            ArrayList Result = new ArrayList();

            if (Count == 0)
            {
                return(Result);
            }
            int i = 0;

            do
            {
                CurveArray CA = new CurveArray();
                Result.Add(CA);
                CA.Add(this[i]);
                while ((i < Count - 1) && ((Curve)this[i]).B.Equals(((Curve)this[i + 1]).A))
                {
                    CA.Add(this[i + 1]);
                    i++;
                }
                i++;
            } while (i < Count);
            if (Result.Count > 1)
            {
                CurveArray First = (CurveArray)Result[0];
                CurveArray Last  = (CurveArray)Result[Result.Count - 1];
                if (((Curve)First[0]).A.Equals(((Curve)Last[Last.Count - 1]).B))
                {
                    for (i = Last.Count - 1; i >= 0; i--)
                    {
                        First.Insert(0, Last[i]);
                    }
                    Result.Remove(Last);
                }
            }
            return(Result);
        }
Example #4
0
        /// <summary>
        /// It`s the same as the overloaded method, but you can set, whether Tangential points
        /// should be taken or not.
        /// </summary>
        /// <param name="value">An other CurveArray</param>
        /// <param name="TangentialPoints">True, if the tangential points are taken</param>
        /// <returns>A Crosslist</returns>
        public CrossList getCrossList(CurveArray value, bool TangentialPoints)
        {
            ArrayList L1 = GetConnections();
            ArrayList L2 = value.GetConnections();

            int       StartJ;
            CrossList CL;
            CrossList Result = new CrossList();

            Result.AllowMultiCross = TangentialPoints;// for instant
            int AIndex = 0;

            for (int i = 0; i < L1.Count; i++)
            {
                CurveArray CA     = (CurveArray)L1[i];
                xyArray    A      = CA.getxyArray();
                int        BIndex = 0;
                StartJ = 0;
                for (int j = StartJ; j < L2.Count; j++)
                {
                    CurveArray CB = (CurveArray)L2[j];
                    xyArray    B  = CB.getxyArray();
                    CL = A.getCrossList(B, TangentialPoints);
                    for (int k = 0; k < CL.Count; k++)
                    {
                        CrossItem CI  = CL[k];
                        double    aID = CA.xyArrayIndexToCurveArrayIndex(CI.Param1);
                        double    bID = CB.xyArrayIndexToCurveArrayIndex(CI.Param2);



                        CI.Param1 = (float)AIndex + CA.xyArrayIndexToCurveArrayIndex(CI.Param1);
                        CI.Param2 = (float)BIndex + CB.xyArrayIndexToCurveArrayIndex(CI.Param2);
                        Curve  C1  = CA[Utils.trunc(aID)];
                        Curve  C2  = CB[Utils.trunc(bID)];
                        double Lam = CI.Param1 - Utils.trunc(CI.Param1);
                        double Mue = CI.Param2 - Utils.trunc(CI.Param2);

                        CI.Param1 = IndexOf(C1) + Lam;
                        CI.Param2 = value.IndexOf(C2) + Mue;
                        Mue       = CI.Param2 - Utils.trunc(CI.Param2);

                        Lam = CI.Param1 - Utils.trunc(CI.Param1);

                        if (C1.Cross(C2, Lam, Mue, out Lam, out Mue))
                        {
                            if ((Lam < 0) && ((System.Math.Abs(Lam) < 0.000001)))
                            {
                                Lam = 0;
                            }
                            if (System.Math.Abs(Lam - 1) < 0.00001)
                            {
                                Lam = 0.999999;
                            }
                            CI.Param1 = Utils.trunc(CI.Param1) + Lam;

                            if ((Mue < 0) && ((System.Math.Abs(Mue) < 0.000001)))
                            {
                                Mue = 0;
                            }
                            if (System.Math.Abs(Mue - 1) < 0.00001)
                            {
                                Mue = 0.999999;
                            }
                            CI.Param2 = Utils.trunc(CI.Param2) + Mue;
                        }

                        else
                        {
                            Lam = 0;
                            if (C1.Equals(C2))
                            {
                                Lam = 1;
                            }
                        }


                        if ((Utils.trunc(CI.Param1) < 0) && (System.Math.Abs(CI.Param1) < 0.00001))
                        {
                            CI.Param1 = 0;
                        }
                        if ((Utils.trunc(CI.Param2) < 0) && (System.Math.Abs(CI.Param2) < 0.00001))
                        {
                            CI.Param2 = 0;
                        }



                        //if (((Utils.trunc(System.Math.Round(CI.Param1,3)) !=System.Math.Round(CI.Param1,3)))
                        //    ||
                        //    ((Utils.trunc(System.Math.Round(CI.Param1,3)) !=System.Math.Round(CI.Param1,3))))
                        Result.Add(CI);
                    }
                    BIndex += CB.Count;
                }
                AIndex += CA.Count;
            }
            return(Result);
        }
Example #5
0
 /// <summary>
 /// Calucalates a <see cref="CrossList"/> for this CurveArray with an other CurveArray.
 /// The CrossItemparameter <see cref="CrossItem.Param1"/> is relative to this CurveArray
 /// and the parameter <see cref="CrossItem.Param2"/>  relative to the "value"-CurveArray.
 /// </summary>
 /// <param name="value">An other CurveArray</param>
 /// <returns>A CrossList</returns>
 public CrossList getCrossList(CurveArray value)
 {
     return(getCrossList(value, false));
 }
Example #6
0
        /// <summary>
        /// activates a <b>CatMull</b> division.
        /// </summary>
        public void CatMull()
        {
            for (int i = 0; i < VertexList.Count; i++)
            {
                Vertex3d V = VertexList[i];
                V.Tag = new SubDivisionDescriptor();
            }

            for (int i = 0; i < FaceList.Count; i++)
            {
                Face F = FaceList[i];
                F.DrawRelativToSurfaceBase = false;
                int n = 0;
                for (int j = 0; j < F.Bounds.Count; j++)
                {
                    xyz      subDivCenter = new xyz(0, 0, 0);
                    EdgeLoop EL           = F.Bounds[j];
                    for (int k = 0; k < EL.Count; k++)
                    {
                        n++;
                        Edge E = EL[k];


                        subDivCenter = subDivCenter + E.EdgeStart.Value;
                    }
                    F.Tag = subDivCenter * (1f / (float)EL.Count);
                }
            }

            for (int i = 0; i < FaceList.Count; i++)
            {
                Face F = FaceList[i];

                int n = 0;
                for (int j = 0; j < F.Bounds.Count; j++)
                {
                    EdgeLoop EL = F.Bounds[j];
                    for (int k = 0; k < EL.Count; k++)
                    {
                        n++;
                        Edge E        = EL[k];
                        Face Neighbor = null;
                        if (E.SameSense)
                        {
                            Neighbor = E.EdgeCurve.Neighbors[1] as Face;
                        }
                        else
                        {
                            Neighbor = E.EdgeCurve.Neighbors[0] as Face;
                        }
                        E.Tag = ((xyz)(E.EdgeCurve.Neighbors[1] as Face).Tag + (xyz)(E.EdgeCurve.Neighbors[0] as Face).Tag + E.EdgeStart.Value + E.EdgeEnd.Value) * (1f / 4f);
                        // Mittelwert der Facepunkte und der Anfangs und Endpunkte im Tag speichern
                        //     E.Tag = ((xyz)F.Tag + (xyz)Neighbor.Tag + E.EdgeStart.Value + E.EdgeEnd.Value) * 0.25;
                        //
                        // den Descriptor im Vertex E.EdgeEnd.Tag updaten
                        SubDivisionDescriptor SDD = E.EdgeEnd.Tag as SubDivisionDescriptor;
                        SDD.Edges.Add(E);
                        SDD.Faces.Add(F);
                    }
                }
            }

            // Update Vertixlist
            xyz Q = new xyz(0, 0, 0);
            xyz R = new xyz(0, 0, 0);

            for (int i = 0; i < VertexList.Count; i++)
            {
                Vertex3d V = VertexList[i];
                SubDivisionDescriptor SDV = V.Tag as SubDivisionDescriptor;
                int n = SDV.Faces.Count;
                if (n == 0)
                {
                    return;
                }
                Q = new xyz(0, 0, 0);
                R = new xyz(0, 0, 0);
                for (int j = 0; j < SDV.Faces.Count; j++)
                {
                    Q = (xyz)SDV.Faces[j].Tag + Q;
                }
                Q = Q * (1f / (float)SDV.Faces.Count);


                for (int j = 0; j < SDV.Edges.Count; j++)
                {
                    R = (xyz)SDV.Edges[j].Tag + R;
                }
                R = R * (1f / (float)SDV.Edges.Count);

                xyz S = V.Value;
                V.Value = (Q + R * 2 + S * (n - 3)) * (1f / (float)n);
            }

            // Kanten Ersetzen
            for (int i = 0; i < FaceList.Count; i++)
            {
                Face F = FaceList[i];



                for (int j = 0; j < F.Bounds.Count; j++)
                {
                    EdgeLoop EL = F.Bounds[j];
                    for (int k = 0; k < EL.Count; k++)
                    {
                        Edge E = EL[k];

                        if (E.SameSense)
                        {
                            E.EdgeCurve.A = E.EdgeStart.Value;
                            E.EdgeCurve.B = E.EdgeEnd.Value;
                        }
                    }
                }
            }

            // Kanten Ersetzen
            for (int i = 0; i < FaceList.Count; i++)
            {
                Face F = FaceList[i];



                for (int j = 0; j < F.Bounds.Count; j++)
                {
                    EdgeLoop EL = F.Bounds[j];
                    for (int k = 0; k < EL.Count; k++)
                    {
                        Edge E = EL[k];
                        if (E.SameSense)
                        {
                            Vertex3d V = new Vertex3d((xyz)E.Tag);

                            insertVertexToSameSenseEdge(F, j, k, V);
                            k++;
                        }
                    }
                }
            }

            FaceList Temp = new FaceList();

            for (int i = 0; i < FaceList.Count; i++)
            {
                Face F = FaceList[i];
                for (int x = 0; x < F.Bounds.Count; x++)
                {
                    EdgeLoop EL = F.Bounds[x];



                    Edge E2 = null;

                    Vertex3d V1 = new Vertex3d();
                    V1.Value = (xyz)F.Tag;
                    VertexList.Add(V1);


                    Vertex3d V4 = null;
                    Vertex3d V2 = null;



                    int startIndex = 1;
                    if (EL[0].EdgeStart.Tag == null) // StartPunkt ist eingefügt
                    {
                        startIndex = 0;
                    }

                    int id = startIndex;

                    int  counter = 0;
                    Edge First   = null;
                    Edge Last    = null;
                    while (id >= 0)
                    {
                        counter++;
                        EdgeLoop newEl = new EdgeLoop();

                        V2 = EL[id].EdgeStart;


                        if (id + 1 < EL.Count)
                        {
                            V4 = EL[id + 1].EdgeEnd;
                        }
                        else
                        {
                            V4 = EL[0].EdgeEnd;
                        }
                        Face newF = new Face();
                        newF.Parent = F.Parent;
                        Temp.Add(newF);


                        EdgeLoop   ELF = new EdgeLoop();
                        List <xyz> Pt  = new List <xyz>();
                        newF.Surface = new PlaneSurface(V1.Value, V2.Value, V4.Value);
                        //    newF.Surface = new PlaneSurface(V1.Value, V2.Value, V4.Value);
                        Edge EA = new Edge();
                        ELF.Add(EA);
                        EdgeList.Add(EA);
                        EA.EdgeStart = V1;
                        EA.EdgeEnd   = V2;
                        if (Last == null)
                        {
                            EA.EdgeCurve = new Line3D(V1.Value, V2.Value);
                            Pt.Add(V1.Value);
                            EdgeCurveList.Add(EA.EdgeCurve);
                            EA.EdgeCurve.Neighbors    = new Face[2];
                            EA.SameSense              = true;
                            EA.EdgeCurve.Neighbors[0] = newF;
                            if (id == startIndex)
                            {
                                First = EA;
                            }
                        }
                        else
                        {
                            EA.EdgeStart = Last.EdgeEnd;
                            Pt.Add(EA.EdgeStart.Value);
                            EA.EdgeEnd   = Last.EdgeStart;
                            EA.EdgeCurve = Last.EdgeCurve;
                            EA.EdgeCurve.Neighbors[1] = newF;
                            EA.SameSense = false;
                        }


                        newF.Bounds.Add(ELF);

                        E2 = EL[id];

                        if (E2.SameSense)
                        {
                            E2.EdgeCurve.Neighbors[0] = newF;
                        }
                        else
                        {
                            E2.EdgeCurve.Neighbors[1] = newF;
                        }
                        Pt.Add(E2.EdgeStart.Value);
                        ELF.Add(E2);


                        Edge E3 = null;
                        if (id + 1 < EL.Count)
                        {
                            E3 = EL[id + 1];
                        }
                        else
                        {
                            E3 = EL[0];
                        }
                        Pt.Add(E3.EdgeStart.Value);
                        if (E3.SameSense)
                        {
                            E3.EdgeCurve.Neighbors[0] = newF;
                        }
                        else
                        {
                            E3.EdgeCurve.Neighbors[1] = newF;
                        }



                        ELF.Add(E3);



                        Edge EE = new Edge();
                        EdgeList.Add(EE);
                        EE.EdgeStart = V4;
                        EE.EdgeEnd   = V1;
                        ELF.Add(EE);
                        Pt.Add(V4.Value);


                        if (counter < 4)
                        {
                            EE.EdgeCurve = new Line3D(EE.EdgeStart.Value, EE.EdgeEnd.Value);
                            EdgeCurveList.Add(EE.EdgeCurve);

                            EE.EdgeCurve.Neighbors    = new Face[2];
                            EE.EdgeCurve.Neighbors[0] = newF;
                            EE.SameSense = true;
                        }
                        else
                        {
                            EE.EdgeCurve = First.EdgeCurve;
                            EE.EdgeStart = First.EdgeEnd;
                            EE.EdgeEnd   = First.EdgeStart;
                            EE.EdgeCurve.Neighbors[1] = newF;
                            EE.SameSense = false;
                        }
                        Last = EE;



                        id++;
                        id++;
                        // newF.Surface = new SmoothPlane(Pt[0],Pt[1],Pt[2],Pt[3], new xyz(1, 0, 0), new xyz(1, 0, 0), new xyz(1, 0, 0), new xyz(1, 0, 0));
                        //     newF.Surface = new SmoothPlane(Pt[0], Pt[1], Pt[2], Pt[3], (Pt[0] - Pt[1]) & (Pt[0] - Pt[3]), (Pt[1] - Pt[0]) & (Pt[1] - Pt[2]), (Pt[2] - Pt[1]) & (Pt[3] - Pt[1]), (Pt[0] - Pt[3]) & (Pt[2] - Pt[3]));
                        if (id + 1 > EL.Count)
                        {
                            break;
                        }

                        //   newF.Surface = new PlaneSurface(V1.Value, V2.Value, V4.Value);
                    }
                }
            }
            FaceList = Temp;
            for (int i = 0; i < FaceList.Count; i++)
            {
                Face F = FaceList[i];
                F.Surface.BoundedCurves = new Loca();
                List <xyz> P  = new List <xyz>();
                xyz        P1 = new xyz(0, 0, 0);
                xyz        P2 = new xyz(0, 0, 0);
                xyz        P3 = new xyz(0, 0, 0);
                xyz        P4 = new xyz(0, 0, 0);

                for (int k = 0; k < F.Bounds.Count; k++)
                {
                    CurveArray CA = new CurveArray();
                    F.Surface.BoundedCurves.Add(CA);
                    for (int l = 0; l < F.Bounds[k].Count; l++)
                    {
                        Edge E = F.Bounds[k][l];

                        CA.Add(new Line(F.Surface.ProjectPoint(E.EdgeStart.Value), F.Surface.ProjectPoint(E.EdgeEnd.Value)));
                        if (l < 4)
                        {
                            P.Add(E.EdgeStart.Value);
                        }
                    }
                    if (i == 3)
                    {
                        List <Edge> L1 = new List <Edge>();
                        for (int j = 0; j < 3; j++)
                        {
                            for (int m = 0; m < FaceList[j].Bounds.Count; m++)
                            {
                                xyz A = new xyz(0, 0, 0);
                                for (int h = 0; h < FaceList[j].Bounds[m].Count; h++)
                                {
                                    Edge E = FaceList[j].Bounds[m][h];

                                    L1.Add(E);
                                }
                            }
                        }

                        for (int h = 0; h < L1.Count; h++)
                        {
                            for (int m = 0; m < L1.Count; m++)
                            {
                                if ((L1[h].EdgeStart.Value.dist(L1[m].EdgeStart.Value) < 0.001) && (h != m))
                                {
                                }
                            }
                        }
                    }
                }

                xyz  n  = ((P[2] - P[0]) & (P[1] - P[0]));
                xyz  m1 = ((P[3] - P[0]) & (P[2] - P[0]));
                Loca L  = F.Surface.BoundedCurves;
                if (i / 2 * 2 == i)
                {
                    F.Surface = new SmoothPlane(P[0], P[1], P[2], P[3], n);
                }
                else
                {
                    F.Surface = new SmoothPlane(P[0], P[1], P[2], P[3], m1);
                }
                F.Surface.BoundedCurves = L;



                //   (P[1] - P[0]) & (P[1] - P[2]), (P[2] - P[1]) & (P[2] - P[3]), (P[3] - P[0]) & (P[3] - P[2]));
                F.DrawRelativToSurfaceBase = false;
            }
        }
Example #7
0
        static List <CrossItem> CreateSortedParams(Face F1, Face F2)
        {
            //------ Erstelle Schnittgerade von F1 und F2---------------
            PlaneSurface S1      = F1.Surface as PlaneSurface;
            PlaneSurface S2      = F2.Surface as PlaneSurface;
            Curve3D      Curve3D = null;

            Curve3D = GetCrossCurve3D(F1, F2); // Schnittgerade der Ebenen
            if (Curve3D == null)
            {
                return(null); // Parallel
            }
            //-----------------------------------------------------------


            List <CrossItem> SortedParams = new List <CrossItem>();
            //---------- Schneide im Parameterraum Face1 mit Schnittgeraden
            Line       L2D = S1.To2dCurve(Curve3D) as Line; // Die Schnittgerade wird auf die Ebene Face1 Projiziert
            CurveArray Ca2 = new CurveArray();

            Ca2.Add(L2D);                 // und in den zweiten CurveArray gestellt

            Loca Loca = F1.ParamCurves;   // die ParamCurves dieser Ebene werden in die Loca gestellt

            double           GlobalIndex = 0;
            List <CrossItem> CrossList   = new List <CrossItem>();

            for (int i = 0; i < Loca.Count; i++)
            {
                CurveArray Ca = Loca[i];

                EdgeLoop  EL = F1.Bounds[i];
                CrossList CL = CrossWithLine(L2D.A, L2D.B, Ca, EL);
                for (int g = 0; g < CL.Count; g++)
                {
                    if (CL[g].Param1 == EL.Count)
                    {
                        CL[g].Param1 = 0;
                    }
                }
                if (CL.Count == 0)
                {
                    continue;
                }                                  // Offener Array oder kein schnittpunkt

                for (int k = 0; k < CL.Count; k++) // Schittpunke der geraden mit Face 1
                {
                    CL[k].Tag     = 1;
                    CL[k].Bound   = i;
                    CL[k].Param1 += GlobalIndex;

                    CL[k].Intern = Ca;
                    CL[k].Face   = F1;
                    if (!(
                            (CL[k].Border1 == BorderBehavior.BorderEnd) && (CL[k].CrossKind == -1)
                            ||
                            (CL[k].Border1 == BorderBehavior.BorderBegin) && (CL[k].CrossKind == 1)
                            ))
                    {
                        ToSortedParams(CrossList, CL[k]); // werden nach Param2 einsortiert
                    }
                }

                GlobalIndex += Loca[i].Count;
            }

            // Analog für Face 2
            // Analog für Face2
            //---------- Schneide um Parameterraum Face2 mit Schnittgeraden
            L2D = S2.To2dCurve(Curve3D) as Line; // Die Schnittgerade wird auf die Ebene Face2 Projiziert
            Ca2 = new CurveArray();
            Ca2.Add(L2D);                        // und in den zweiten CurveArray gestellt

            // die ParamCurves dieser Ebene werden in die Loca gestellt
            Loca = F2.ParamCurves;

            GlobalIndex = 0;

            for (int j = 0; j < Loca.Count; j++)
            {
                EdgeLoop   EL = F2.Bounds[j];
                CurveArray Ca = Loca[j];
                CrossList  CL = CrossWithLine(L2D.A, L2D.B, Ca, EL);
                for (int g = 0; g < CL.Count; g++)
                {
                    if (CL[g].Param1 == EL.Count)
                    {
                        CL[g].Param1 = 0;
                    }
                }
                if (CL.Count == 0)
                {
                    continue;
                }                                  // Offener Array oder kein schnittpunkt
                for (int k = 0; k < CL.Count; k++) // Schittpunke der geraden mit Face 2
                {
                    CL[k].Tag     = 2;
                    CL[k].Bound   = j;
                    CL[k].Param1 += GlobalIndex;
                    CL[k].Intern  = Ca;
                    CL[k].Face    = F2;
                    if (!(
                            (CL[k].Border1 == BorderBehavior.BorderEnd) && (CL[k].CrossKind == -1)
                            ||
                            (CL[k].Border1 == BorderBehavior.BorderBegin) && (CL[k].CrossKind == 1)
                            ))
                    {
                        ToSortedParams(CrossList, CL[k]); // werden nach Param1 einsortiert
                    }
                    else
                    {
                    }
                }

                GlobalIndex += Loca[j].Count;
            }
            if (CrossList.Count > 4)
            {
            }
            int Face1Status = 0;
            int Face2Status = 0;
            int id          = 0;

            while (id < CrossList.Count)
            {
                if ((int)CrossList[id].Tag == 1)
                {
                    Face1Status += CrossList[id].CrossKind;
                }
                if ((int)CrossList[id].Tag == 2)
                {
                    Face2Status += CrossList[id].CrossKind;
                }

                //if (id < CrossList.Count-1)
                if ((Face2Status == 0) && (Face1Status == 0))
                {
                    if (id > 0)
                    {
                        if ((int)CrossList[id - 1].Tag == (int)CrossList[id].Tag)
                        {
                            if (id + 1 < CrossList.Count)
                            {
                                if (System.Math.Abs(CrossList[id + 1].Param2 - CrossList[id].Param2) > 0.000001)
                                {
                                    CrossList.RemoveAt(id - 1);
                                    CrossList.RemoveAt(id - 1);
                                    id--;
                                }
                                else
                                {
                                    id++;
                                }
                            }
                        }
                        else
                        {
                            id++;
                        }
                    }
                }
                else
                {
                    id++;
                }
            }

            return(CrossList);
        }