示例#1
0
 private bool showCirc()
 {
     block = Block.Construct();
     for (int i = 1; i < copCount; ++i)
     {
         GeoObjectList li = new GeoObjectList();
         // für jede Kopie ein Clone machen
         li = originals.CloneObjects();
         ModOp m = ModOp.Rotate(rotationPoint, base.ActiveDrawingPlane.Normal, i * copAngle);
         if (!objRot) // Objekte drehen mit: einfach modifizieren
         {
             li.Modify(m);
         }
         else
         {   // Objekte drehen nicht mit: Translation des gedrehten centerpoints
             ModOp mt = ModOp.Translate(new GeoVector(centerPoint, m * centerPoint));
             li.Modify(mt);
         }
         block.Add(li);
     }
     if (block.Count > 0)
     {
         base.ActiveObject = block;
         return(true);
     }
     else
     {
         base.ActiveObject = null;
         return(false);
     }
 }
示例#2
0
 private void RotateWithPlanes()
 {
     // get rotation axis from the two planes
     if (src.Intersect(trg, out GeoPoint loc, out GeoVector dir))
     {
         // set to original position
         for (int i = 0; i < block.Count; ++i)
         {
             block.Child(i).CopyGeometry(originals[i]);
         }
         Plane       perp = new Plane(loc, dir); // plane perpendicular to rotation axis
         GeoVector2D from = perp.Project(dir ^ src.Normal);
         GeoVector2D to   = perp.Project(dir ^ trg.Normal);
         SweepAngle  sw   = new SweepAngle(from, to);
         rotationAngle = sw;
         rotAngleInput.ForceValue(rotationAngle);
         ModOp     m0 = ModOp.Rotate(loc, dir, sw);
         ModOp     m1 = ModOp.Rotate(loc, -dir, sw);
         GeoVector n0 = m0 * src.Normal;
         GeoVector n1 = m1 * src.Normal;
         ModOp     m; // not sure, which rotation is better
         if (Math.Abs(n0 * trg.Normal) > Math.Abs(n1 * trg.Normal))
         {
             m          = ModOp.Rotate(loc, dir, sw + GetOffset());
             axisVector = dir;
         }
         else
         {
             m          = ModOp.Rotate(loc, -dir, sw + GetOffset());
             axisVector = -dir;
         }
         block.Modify(m);
         base.BasePoint = loc;
     }
 }
示例#3
0
 public override void OnDone()
 {
     // ist die Shift Taste gehalten, so werden Kopien gemacht, d.h. der die Elemente
     // des blocks werden eingefügt. Ansonsten werden die original-Objekte verändert
     // TODO: Feedback über Cursor bei Shift-Taste fehlt noch
     // TODO: die neuen oder veränderten Objekte sollten markiert sein.
     using (Frame.Project.Undo.UndoFrame)
     {
         //				ModOp m = ModOp.Rotate(base.BasePoint,base.ActiveDrawingPlane.Normal,new SweepAngle(rotationAngle));
         ModOp m = ModOp.Rotate(base.BasePoint, axisVector, new SweepAngle(rotationAngle) + GetOffset());
         if (((Frame.UIService.ModifierKeys & Keys.Shift) != 0) || copyObject)
         {
             GeoObjectList cloned = new GeoObjectList();
             foreach (IGeoObject go in originals)
             {
                 IGeoObject cl = go.Clone();
                 cl.Modify(m);
                 cloned.Add(cl);
             }
             base.Frame.Project.GetActiveModel().Add(cloned);
         }
         else
         {
             originals.Modify(m);
         }
     }
     base.ActiveObject = null; // damit es nicht gleich eingefügt wird
     base.OnDone();
 }
示例#4
0
        /// <summary>
        /// Overrides <see cref="CADability.GeoObject.ISurfaceImpl.PointAt (GeoPoint2D)"/>
        /// </summary>
        /// <param name="uv"></param>
        /// <returns></returns>
        public override GeoPoint PointAt(GeoPoint2D uv)
        {
            double     pos       = GetPos(uv.y);
            GeoPoint2D p2d       = basisCurve2D.PointAt(pos);
            ModOp      rot       = ModOp.Rotate(1, (SweepAngle)uv.x);
            ModOp      movePitch = ModOp.Translate(0, pitch * uv.x / (Math.PI * 2.0), 0);

            return(toSurface * movePitch * rot * p2d);
        }
示例#5
0
        /// <summary>
        /// Overrides <see cref="CADability.GeoObject.ISurfaceImpl.FixedU (double, double, double)"/>
        /// </summary>
        /// <param name="u"></param>
        /// <param name="vmin"></param>
        /// <param name="vmax"></param>
        /// <returns></returns>
        public override ICurve FixedU(double u, double vmin, double vmax)
        {
            ICurve2D btr       = basisCurve2D.Trim(GetPos(vmin), GetPos(vmax));
            ICurve   b3d       = btr.MakeGeoObject(Plane.XYPlane) as ICurve;
            ModOp    rot       = ModOp.Rotate(1, (SweepAngle)u);
            ModOp    movePitch = ModOp.Translate(0, pitch * u / (Math.PI * 2.0), 0);

            return(b3d.CloneModified(toSurface * movePitch * rot));
        }
示例#6
0
 private void ReflectLineChanged(CurveInput sender, ICurve SelectedCurve)
 {
     for (int i = 0; i < originals.Count; ++i)
     { // Urzustand
         block.Item(i).CopyGeometry(originals[i]);
     }  // nun drehen um 180 Grad
     reflectModOp = ModOp.Rotate(SelectedCurve.StartPoint, SelectedCurve.StartDirection, new SweepAngle(Math.PI));
     block.Modify(reflectModOp);
 }
示例#7
0
        private bool OnSetRotationAngle(Angle angle)
        {
            ModOp m = ModOp.Rotate(base.BasePoint, axisVector, new SweepAngle(angle - rotationAngle) + GetOffset());

            block.Modify(m);
            base.ActiveObject = block;
            rotationAngle     = angle;
            return(true);
        }
示例#8
0
        private void OnSetLatitude(Angle a)
        {
            GeoVector l  = Frame.ActiveView.Projection.DrawingPlane.ToLocal(GetGeoVector());
            GeoVector nl = new GeoVector(l.x, l.y, 0);

            nl.Length = l.Length;
            ModOp rot = ModOp.Rotate(nl ^ Frame.ActiveView.Projection.DrawingPlane.Normal, a); // cross product correct?

            SetValue(Frame.ActiveView.Projection.DrawingPlane.ToGlobal(rot * nl), true);
        }
示例#9
0
        /// <summary>
        /// Overrides <see cref="CADability.GeoObject.ISurfaceImpl.VDirection (GeoPoint2D)"/>
        /// </summary>
        /// <param name="uv"></param>
        /// <returns></returns>
        public override GeoVector VDirection(GeoPoint2D uv)
        {
            double      pos = GetPos(uv.y);
            GeoVector2D dir = basisCurve2D.DirectionAt(pos);
            //dir = (1.0 / (curveEndParameter - curveStartParameter)) * dir; // dir ist die Änderung um 1 also volle Kurvenlänge
            // 15.8.17: die Skalierung von dir ist wohl falsch: NewtonLineintersection läuft mit obiger Zeile nicht richtig, so aber perfekt
            // pitch fehlt noch, ist vermutlich nicht nötig
            ModOp rot = ModOp.Rotate(1, (SweepAngle)uv.x);

            return(toSurface * rot * dir);
        }
示例#10
0
 private void OnSetEndPoint(GeoPoint p)
 {
     endPoint = p;
     if (startPointInput.Fixed)
     {
         rotAngleInput.Fixed = true; // damit die Aktion nach dem Endpunkt aufhört
         SweepAngle swAngle = new SweepAngle((GeoVector2D)(base.ActiveDrawingPlane.Project(startPoint) - base.ActiveDrawingPlane.Project(refPoint)), base.ActiveDrawingPlane.Project(endPoint) - base.ActiveDrawingPlane.Project(refPoint));
         ModOp      m       = ModOp.Rotate(base.BasePoint, axisVector, new SweepAngle(swAngle - rotationAngle) + GetOffset());
         rotationAngle = swAngle.Radian;
         block.Modify(m);
         feedBackEllipse.SetArcPlaneCenterStartEndPoint(ActiveDrawingPlane, ActiveDrawingPlane.Project(BasePoint), ActiveDrawingPlane.Project(startPoint), ActiveDrawingPlane.Project(endPoint), ActiveDrawingPlane, swAngle.Radian > 0.0);
     }
 }
示例#11
0
        private void RotateLineChanged(CurveInput sender, ICurve SelectedCurve)
        {
            base.BasePoint = SelectedCurve.StartPoint;
            axisVector     = SelectedCurve.StartDirection;
            // erstmal den Urprungszustand herstellen
            for (int i = 0; i < block.Count; ++i)
            {
                block.Child(i).CopyGeometry(originals[i]);
            }
            ModOp m = ModOp.Rotate(base.BasePoint, axisVector, new SweepAngle(rotationAngle) + GetOffset());

            block.Modify(m);
        }
示例#12
0
 private void SetRefPoint(GeoPoint p)
 {
     refPoint       = p;
     block.RefPoint = p;
     base.BasePoint = p; // für die Winkelberechnung
     if (rotAngleInput.Fixed)
     {
         for (int i = 0; i < block.Count; ++i)
         {
             block.Child(i).CopyGeometry(originals[i]);
         }
         ModOp m = ModOp.Rotate(base.BasePoint, axisVector, new SweepAngle(rotationAngle) + GetOffset());
         block.Modify(m);
     }
 }
示例#13
0
        private bool RotateLine(CurveInput sender, ICurve[] Curves, bool up)
        {   // ... nur die sinnvolen Kurven verwenden
            ArrayList usableCurves = new ArrayList();
            ModOp     m;

            for (int i = 0; i < Curves.Length; ++i)
            {
                Line l = Curves[i] as Line;
                if (l != null)
                {
                    usableCurves.Add(Curves[i]);
                }
            }
            // ...hier wird der ursprüngliche Parameter überschrieben. Hat ja keine Auswirkung nach außen.
            Curves = (ICurve[])usableCurves.ToArray(typeof(ICurve));
            if (up)
            {
                if (Curves.Length == 0)
                {
                    sender.SetCurves(Curves, null);                     // ...die werden jetzt im ControlCenter dargestellt (nur bei up)
                }
                else
                { // erst jetzt die Werte merken!
                    base.BasePoint = Curves[0].StartPoint;
                    axisVector     = Curves[0].StartDirection;
                    sender.SetCurves(Curves, Curves[0]);
                }
            }
            // erstmal den Urprungszustand herstellen, da sonst Drehungg akkumuliert wird
            for (int i = 0; i < block.Count; ++i)
            {
                block.Child(i).CopyGeometry(originals[i]);
            }
            if (Curves.Length > 0)
            {   // einfach die erste Kurve nehmen
                ICurve iCurve = Curves[0];
                m = ModOp.Rotate(iCurve.StartPoint, iCurve.StartDirection, new SweepAngle(rotationAngle) + GetOffset());
                block.Modify(m);
                return(true);
            }
            // rückgängig!
            m = ModOp.Rotate(base.BasePoint, axisVector, new SweepAngle(rotationAngle) + GetOffset());
            block.Modify(m);
            return(false);
        }
示例#14
0
        private bool ReflectLine(CurveInput sender, ICurve[] Curves, bool up)
        {   // ... nur die sinnvolen Kurven verwenden
            ArrayList usableCurves = new ArrayList();

            for (int i = 0; i < Curves.Length; ++i)
            {
                Line l = Curves[i] as Line;
                if (l != null)
                {
                    usableCurves.Add(Curves[i]);
                }
            }
            // ...hier wird der ursprüngliche Parameter überschrieben. Hat ja keine Auswirkung nach außen.
            Curves = (ICurve[])usableCurves.ToArray(typeof(ICurve));
            if (up)
            {
                if (Curves.Length == 0)
                {
                    sender.SetCurves(Curves, null); // ...die werden jetzt im ControlCenter dargestellt (nur bei up)
                    OnDone();
                    return(true);
                }
                else
                {
                    sender.SetCurves(Curves, Curves[0]);
                }
            }
            for (int i = 0; i < originals.Count; ++i)
            { // Urzustand
                block.Item(i).CopyGeometry(originals[i]);
            }
            if (Curves.Length > 0)
            {                              // einfach die erste Kurve nehmen
                ICurve iCurve = Curves[0]; // nun drehen um 180 Grad
                reflectModOp = ModOp.Rotate(iCurve.StartPoint, iCurve.StartDirection, new SweepAngle(Math.PI));
                block.Modify(reflectModOp);
                return(true);
            }
            reflectModOp = reflectModOpStart; // zurücksetzen
            block.Modify(reflectModOp);
            return(false);
        }
示例#15
0
        public override void Derivation2At(GeoPoint2D uv, out GeoPoint location, out GeoVector du, out GeoVector dv, out GeoVector duu, out GeoVector dvv, out GeoVector duv)
        {
            location = PointAt(uv);
            du       = UDirection(uv);
            dv       = VDirection(uv);
            double     pos = GetPos(uv.y);
            GeoPoint2D p2d = basisCurve2D.PointAt(pos);

            duu = new GeoVector(-Math.Cos(uv.x), 0.0, -Math.Sin(uv.x));
            GeoVector2D deriv1, deriv2;

            if (basisCurve2D.TryPointDeriv2At(pos, out p2d, out deriv1, out deriv2))
            {
                ModOp rot = ModOp.Rotate(1, (SweepAngle)uv.x);
                dvv = toSurface * rot * deriv2;
                duv = GeoVector.NullVector;
            }
            else
            {
                dvv = GeoVector.NullVector;
                duv = GeoVector.NullVector;
            }
        }
示例#16
0
        private bool rotateOrg()
        {
            if (selectedObjectsList == null)
            {
                return(false);
            }
            IGeoObject iGeoObjectSel;

            blk = Block.Construct(); // zur Darstellung
            if (base.ActiveObject != null)
            {
                blk.CopyAttributes(base.ActiveObject);
            }
            // der block wird das neue aktive Objekt, er muss die Attribute tragen, weil sie später
            // wieder von ihm verlangt werden
            Boolean success = false;                                  // hat er wenigstens eins gefunden

            for (int i = 0; i < selectedObjectsList.Count; i++)       // läuft über alle selektierten Objekte. Evtl nur eins bei Konstruktion
            {
                iGeoObjectSel               = selectedObjectsList[i]; // zur Vereinfachung
                geoObjectOrgList[i]         = iGeoObjectSel;          // zum Weglöschen des Originals in onDone
                ownerList[i]                = iGeoObjectSel.Owner;    // owner merken für löschen
                pathCreatedFromModelList[i] = null;
                shapeList[i]                = null;
                Path p = null;
                if (iGeoObjectSel is ICurve)
                {
                    p = CADability.GeoObject.Path.CreateFromModel(iGeoObjectSel as ICurve, Frame.ActiveView.Model, Frame.ActiveView.Projection, true);
                    if (p == null)
                    {     // also nur Einzelelement
                        if (iGeoObjectSel is Path)
                        { // schon fertig
                            p = iGeoObjectSel.Clone() as Path;
                        }
                        else
                        {  // Pfad aus Einzelobjekt machen:
                            p = Path.Construct();
                            p.Set(new ICurve[] { iGeoObjectSel.Clone() as ICurve });
                        }
                    }
                    else
                    {                                       // CreateFromModel hat was zusammengesetzt
                        geoObjectOrgList[i]         = null; // zum nicht Weglöschen des Originals in onDone
                        pathCreatedFromModelList[i] = p;    // kopie merken für onDone
                        p = p.Clone() as Path;
                        p.Flatten();
                    }
                    if (p != null)
                    { //
                        if (angleOffsetRotation != 0.0)
                        {
                            ModOp m = ModOp.Rotate(axisPoint, axisVector, new SweepAngle(angleOffsetRotation));
                            p.Modify(m);
                        }
                        double sw = angleRotation;
                        if (sw == 0.0)
                        {
                            sw = Math.PI * 2.0;
                        }
                        IGeoObject shape = Make3D.MakeRevolution(p, axisPoint, axisVector, sw, Frame.Project);
                        if (shape != null)
                        {
                            shape.CopyAttributes(blk);
                            // die Attribute müssen vom Block übernommen werden
                            shapeList[i] = shape;         // fertiger Körper in shapeList
                            blk.Add(shape);               // zum Darstellen
                            base.FeedBack.AddSelected(p); // zum Markieren des Ursprungsobjekts
                            success = true;
                        }
                    }
                }
            }
            if (success)
            {
                base.ActiveObject     = blk; // darstellen
                base.ShowActiveObject = true;
                return(true);
            }
            else
            {
                optionalOrg();
                base.ShowActiveObject = false;
                base.FeedBack.ClearSelected();
                return(false);
            }
        }
示例#17
0
        public override void OnMouseMove(MouseEventArgs e, IView vw)
        {
            if (e.Button != MouseButtons.Left)
            {
                return;
            }
            if (modelView == null)
            {
                return;
            }
            int HOffset = e.X - lastPanPosition.X;
            int VOffset = e.Y - lastPanPosition.Y;

            if (VOffset != 0 || HOffset != 0)
            {
                Projection Projection = vw.Projection;
                lastPanPosition = new Point(e.X, e.Y);
                GeoVector haxis = Projection.InverseProjection * GeoVector.XAxis;
                GeoVector vaxis = Projection.InverseProjection * GeoVector.YAxis;
                ModOp     mh    = ModOp.Rotate(vaxis, SweepAngle.Deg(HOffset / 5.0));
                ModOp     mv    = ModOp.Rotate(haxis, SweepAngle.Deg(VOffset / 5.0));

                ModOp project = Projection.UnscaledProjection * mv * mh;
                // jetzt noch die Z-Achse einrichten. Die kann senkrecht nach oben oder unten
                // zeigen. Wenn die Z-Achse genau auf den Betrachter zeigt oder genau von ihm weg,
                // dann wird keine Anpassung vorgenommen, weils sonst zu sehr wackelt
                GeoVector z = project * GeoVector.ZAxis;
                if (modelView.ZAxisUp)
                {
                    const double mindeg = 0.05; // nur etwas aufrichten, aber in jedem Durchlauf
                    if (z.y < -0.1)
                    {                           // Z-Achse soll nach unten zeigen
                        Angle a = new Angle(-GeoVector2D.YAxis, new GeoVector2D(z.x, z.y));
                        if (a.Radian > mindeg)
                        {
                            a.Radian = mindeg;
                        }
                        if (a.Radian < -mindeg)
                        {
                            a.Radian = -mindeg;
                        }
                        if (z.x < 0)
                        {
                            project = project * ModOp.Rotate(vaxis ^ haxis, -a.Radian);
                        }
                        else
                        {
                            project = project * ModOp.Rotate(vaxis ^ haxis, a.Radian);
                        }
                        z = project * GeoVector.ZAxis;
                    }
                    else if (z.y > 0.1)
                    {
                        Angle a = new Angle(GeoVector2D.YAxis, new GeoVector2D(z.x, z.y));
                        if (a.Radian > mindeg)
                        {
                            a.Radian = mindeg;
                        }
                        if (a.Radian < -mindeg)
                        {
                            a.Radian = -mindeg;
                        }
                        if (z.x < 0)
                        {
                            project = project * ModOp.Rotate(vaxis ^ haxis, a.Radian);
                        }
                        else
                        {
                            project = project * ModOp.Rotate(vaxis ^ haxis, -a.Radian);
                        }
                        z = project * GeoVector.ZAxis;
                    }
                }
                // Fixpunkt bestimmen
                Point clcenter = vw.Canvas.ClientRectangle.Location;
                clcenter.X += vw.Canvas.ClientRectangle.Width / 2;
                clcenter.Y += vw.Canvas.ClientRectangle.Height / 2;
                // ium Folgenden ist Temporary auf true zu setzen und ein Mechanismus zu finden
                // wie der QuadTree von ProjektedModel berechnet werden soll
                //GeoVector newDirection = mv * mh * Projection.Direction;
                //GeoVector oldDirection = Projection.Direction;
                //GeoVector perp = oldDirection ^ newDirection;

                GeoPoint fixpoint;
                //if (Settings.GlobalSettings.ContainsSetting("ViewFixPoint"))
                if (modelView != null && modelView.FixPointValid)
                {
                    //fixpoint = (GeoPoint)Settings.GlobalSettings.GetValue("ViewFixPoint");
                    fixpoint = modelView.FixPoint;
                }
                else
                {
                    fixpoint = Projection.UnProject(clcenter);
                }
                modelView.SetViewDirection(project, fixpoint, true);
                if (Math.Abs(HOffset) > Math.Abs(VOffset))
                {
                    if (HOffset > 0)
                    {
                        vw.Canvas.Cursor = "PanEast";
                    }
                    else
                    {
                        vw.Canvas.Cursor = "PanWest";
                    }
                }
                else
                {
                    if (HOffset > 0)
                    {
                        vw.Canvas.Cursor = "PanSouth";
                    }
                    else
                    {
                        vw.Canvas.Cursor = "PanNorth";
                    }
                }
                modelView.projectedModelNeedsRecalc = false;
            }
        }
示例#18
0
 ModOp IMovement.GetPosition(double u)
 {
     return(ModOp.Rotate(axis.Location, axis.Direction, new SweepAngle(u)));
 }
示例#19
0
        /// <summary>
        /// Constructs a non periodic spherical surface with <paramref name="center"/> and <paramref name="radius"/>. The z-axis will be oriented
        /// so that the "south pole" falls into an unused part of the sphere. The edges are <paramref name="orientedCurves"/> bound the sphere
        /// so that when you walk along the curve (<paramref name="outwardOriented"/>==true: on the outside, false: on the inside of the sphere), the
        /// used surfaces is on the left side of the curve. The curves must all be connected and define one or more closed loops on the surface.
        /// </summary>
        /// <param name="center"></param>
        /// <param name="radius"></param>
        /// <param name="outwardOriented">true: the center is on the inside, false: the center is on the outside of the surface</param>
        /// <param name="orientedCurves"></param>
        public SphericalSurfaceNP(GeoPoint center, double radius, bool outwardOriented, ICurve[] orientedCurves)
        {   // find all intersection points of the curves with a plane through the center
            // the points must be on a circle (because the curves are on the sphere) and alternating enter and leave the used surface.
            // we look for the biggest part outside the surface and use its center as the south pole
            for (int ii = 0; ii < 2; ii++)
            {   // if the first loop doesn't find a solution, run with different points again
                // exactly 3 arcs, which define an octant of the sphere can make a problem
                for (int i = 0; i < orientedCurves.Length; i++)
                {
                    double pos = 0.45;
                    if (ii == 1)
                    {
                        pos = 0.55;
                    }
                    GeoPoint  p    = orientedCurves[i].PointAt(pos); // not exactly in the middle to avoid special cases
                    GeoVector dir  = orientedCurves[i].DirectionAt(pos);
                    GeoVector xdir = p - center;
                    Plane     pln;
                    if (outwardOriented)
                    {
                        pln = new Plane(center, xdir, dir ^ xdir);
                    }
                    else
                    {
                        pln = new Plane(center, xdir, xdir ^ dir);
                    }
                    if (ii == 1)
                    {
                        pln.Modify(ModOp.Rotate(center, xdir, SweepAngle.Deg(5))); // slightly rotate to not go exactly through a vertex
                    }
                    double[] pi = orientedCurves[i].GetPlaneIntersection(pln);
                    SortedDictionary <double, bool> positions = new SortedDictionary <double, bool>();
                    bool ok = false;
                    for (int j = 0; j < pi.Length; j++)
                    {
                        GeoPoint2D pi2d = pln.Project(orientedCurves[i].PointAt(pi[j]));
                        double     a    = Math.Atan2(pi2d.y, pi2d.x);
                        if (Math.Abs(pi[j] - pos) < 1e-6)
                        {
                            ok = true;
                            a  = 0.0;
                        }
                        if (positions.ContainsKey(a))
                        {
                            ok = false;
                            break;
                        }
                        else
                        {
                            positions[a] = outwardOriented ^ (pln.ToLocal(orientedCurves[i].DirectionAt(pi[j])).z > 0);
                        }
                    }
                    if (ok)
                    {
                        for (int k = 0; k < orientedCurves.Length; k++)
                        {
                            if (k == i)
                            {
                                continue;
                            }
                            pi = orientedCurves[k].GetPlaneIntersection(pln);
                            for (int j = 0; j < pi.Length; j++)
                            {
                                GeoPoint2D pi2d = pln.Project(orientedCurves[k].PointAt(pi[j]));
                                double     a    = Math.Atan2(pi2d.y, pi2d.x);
                                if (a < 0)
                                {
                                    a += Math.PI * 2.0;
                                }
                                if (positions.ContainsKey(a))
                                {
                                    ok = false;
                                    break;
                                }
                                else
                                {
                                    positions[a] = outwardOriented ^ (pln.ToLocal(orientedCurves[k].DirectionAt(pi[j])).z > 0);
                                }
                            }
                            if (!ok)
                            {
                                break;      // two identical intersection points
                            }
                        }
                    }
                    if (ok)
                    {
                        double lastPos = -1;
                        bool   lastEnter = false;
                        double sp = 0, d = double.MinValue;
                        foreach (KeyValuePair <double, bool> position in positions)
                        {
                            if (lastPos >= 0)
                            {
                                if (position.Value == lastEnter)
                                {
                                    ok = false; // must be alternating
                                    break;
                                }
                                if (position.Value && position.Key - lastPos > d)
                                {
                                    d  = position.Key - lastPos;
                                    sp = lastPos;
                                }
                            }
                            lastPos   = position.Key;
                            lastEnter = position.Value;
                        }
                        GeoPoint2D soutPole2d = new GeoPoint2D(radius * Math.Cos(sp + d / 2), radius * Math.Sin(sp + d / 2));
                        if (ok && d > double.MinValue)
                        {
                            this.center = center;
                            zAxis       = center - pln.ToGlobal(soutPole2d);
                            zAxis.ArbitraryNormals(out xAxis, out yAxis);
                            if (!outwardOriented)
                            {
                                xAxis = -xAxis;
                            }
                            xAxis.Length = zAxis.Length;
                            yAxis.Length = zAxis.Length;
                        }
                        else
                        {
                            ok = false;
                        }
                    }
#if DEBUG
                    // GeoObjectList dbg = DebugGrid;
#endif
                    if (ok)
                    {
                        return;
                    }
                }
            }
        }