Example #1
0
        void IView.ZoomToRect(BoundingRect World2D)
        {
            Rectangle screen = (this as IView).DisplayRectangle;
            double    factor;

            // Höhe und Breite==0 soll einen Fehler liefern!
            if (World2D.Height == 0.0)
            {
                factor = screen.Width / World2D.Width;
            }
            else if (World2D.Width == 0.0)
            {
                factor = screen.Height / World2D.Height;
            }
            else
            {
                factor = Math.Min(screen.Width / World2D.Width, screen.Height / World2D.Height);
            }
            // wie ist das mit der Y-Richtung in screen?
            double dx = (screen.Right + screen.Left) / 2.0 - (World2D.Right + World2D.Left) / 2.0 * factor;
            double dy = (screen.Top + screen.Bottom) / 2.0 + (World2D.Top + World2D.Bottom) / 2.0 * factor;

            layoutToScreen = new ModOp2D(factor, 0.0, dx, 0.0, -factor, dy);
            screenToLayout = layoutToScreen.GetInverse(); // ginge auch einfacher
        }
Example #2
0
 public ScaledSurface(ISurface original, double fu, double fv)
 {
     this.fu       = fu;
     this.fv       = fv;
     this.original = original;
     scale         = ModOp2D.Scale(fu, fv);
     unscale       = scale.GetInverse();
 }
Example #3
0
        public override double PositionOf(GeoPoint2D p)
        {
            ModOp2D toUnit = fromUnit.GetInverse();
            double  u      = (toUnit * p).x;

#if DEBUG
            GeoPoint2D tp = PointAt(ParToPos(u));
            double     d  = p | tp;
#endif
            return(ParToPos(u));
        }
Example #4
0
        private void Init(bool uPeriodic)
        {
            hasPole    = false;
            fullPeriod = false;
            if (uPeriodic)
            {
                fullPeriod = true;
                double[] sv = periodicSurface.GetVSingularities();
                if (sv != null && sv.Length > 1)
                {
                    List <double> lsv = new List <double>(sv);
                    for (int i = lsv.Count - 1; i >= 0; --i)
                    {
                        if (lsv[i] < periodicBounds.Bottom || lsv[i] > periodicBounds.Top)
                        {
                            lsv.RemoveAt(i);
                        }
                    }
                    sv = lsv.ToArray();
                }
                if (sv != null && sv.Length > 0)
                {
                    if (sv.Length == 1)
                    {
                        hasPole = true;
                        if (sv[0] == periodicBounds.Bottom)
                        {
                            // bounds.Bottom => 0.0, bounds.Top => 1.0
                            // bounds.Left => 0, bountd.Right => 2*pi
                            double fvu = 2.0 * Math.PI / periodicBounds.Width;
                            double fuv = 1.0 / periodicBounds.Height;
                            toNonPeriodicBounds = new ModOp2D(fvu, 0, -fvu * periodicBounds.Left, 0, fuv, -fuv * periodicBounds.Bottom);
                        }
                        else if (sv[0] == periodicBounds.Top)
                        {
                            // bounds.Bottom => 0.0, bounds.Top => 1.0
                            // bounds.Left => 2*pi, bountd.Right => 0
                            double fvu = 2.0 * Math.PI / periodicBounds.Width;
                            double fuv = 1.0 / periodicBounds.Height;
                            toNonPeriodicBounds = new ModOp2D(-fvu, 0, fvu * periodicBounds.Right, 0, fuv, -fuv * periodicBounds.Bottom);
                        }
                        else
                        {
                            throw new ApplicationException("pole must be on border");
                        }
                    }
                    else
                    {
                        throw new ApplicationException("more than one pole");
                    }
                }
                else
                {
                    // bounds.Bottom => 0.5, bounds.Top => 1.5
                    // bounds.Left => 0, bountd.Right => 2*pi
                    double fvu = -2.0 * Math.PI / periodicBounds.Width; // "-", because toroidal surface needs it for correct orientation. What about NURBS?
                    double fuv = 1.0 / periodicBounds.Height;
                    toNonPeriodicBounds = new ModOp2D(fvu, 0, -fvu * periodicBounds.Left - Math.PI, 0, fuv, -fuv * periodicBounds.Bottom + 0.5);
                }
            }
            else if (periodicSurface.IsVPeriodic)
            {
                fullPeriod = true;
                double[] su = periodicSurface.GetUSingularities();
                if (su != null && su.Length > 1)
                {
                    List <double> lsu = new List <double>(su);
                    for (int i = lsu.Count - 1; i >= 0; --i)
                    {
                        if (lsu[i] < periodicBounds.Left || lsu[i] > periodicBounds.Right)
                        {
                            lsu.RemoveAt(i);
                        }
                    }
                    su = lsu.ToArray();
                }
                if (su != null && su.Length > 0)
                {
                    if (su.Length == 1)
                    {
                        hasPole = true;
                        if (su[0] == periodicBounds.Left)
                        {
                            double fvu = 2.0 * Math.PI / periodicBounds.Height;
                            double fuv = 1.0 / periodicBounds.Width;
                            toNonPeriodicBounds = new ModOp2D(0, fvu, -fvu * periodicBounds.Bottom, fuv, 0, -fuv * periodicBounds.Left);
                        }
                        else if (su[0] == periodicBounds.Right)
                        {
                            double fvu = 2.0 * Math.PI / periodicBounds.Height;
                            double fuv = 1.0 / periodicBounds.Width;
                            toNonPeriodicBounds = new ModOp2D(0, -fvu, fvu * periodicBounds.Top, fuv, 0, -fuv * periodicBounds.Left);
                        }
                        else
                        {
                            throw new ApplicationException("pole must be on border");
                        }
                    }
                    else
                    {
                        throw new ApplicationException("more than one pole");
                    }
                }
                else
                {
                    double fvu = 2.0 * Math.PI / periodicBounds.Height;
                    double fuv = 1.0 / periodicBounds.Width;
                    toNonPeriodicBounds = new ModOp2D(0, fvu, -fvu * periodicBounds.Bottom, fuv, 0, -fuv * periodicBounds.Left + 0.5);
                }
            }
            else
            {   // not periodic, only pole removal
                // map the "periodic" parameter (where there is a singularity) onto [0..pi/2], the other parameter to [0..1]
                bool     done = false;
                double[] su   = periodicSurface.GetUSingularities();
                if (su != null && su.Length == 1)
                {   // the "period" to be resolved is in v, when u==su[0] you can change v and the point stays fixed
                    hasPole = true;
                    if (Math.Abs(su[0] - periodicBounds.Left) < periodicBounds.Width * 1e-6)
                    {                                                       // we have to map the v interval of the periodic surface onto [0..pi/2] and the u interval onto [0..1]
                        // and we also have to exchange u and v, so the non periodic bounds are [0..pi/2] in u and [0..1] in v
                        double fvu = Math.PI / 2.0 / periodicBounds.Height; // tested: ok
                        double fuv = 1.0 / periodicBounds.Width;
                        toNonPeriodicBounds = new ModOp2D(0, fvu, -fvu * periodicBounds.Bottom, fuv, 0, -fuv * periodicBounds.Left);
                    }
                    else if (Math.Abs(su[0] - periodicBounds.Right) < periodicBounds.Width * 1e-6)
                    {                                                       // here we additionally have tor reverse the v interval
                        double fvu = Math.PI / 2.0 / periodicBounds.Height; // tested: ok
                        double fuv = 1.0 / periodicBounds.Width;
                        toNonPeriodicBounds = new ModOp2D(0, -fvu, fvu * periodicBounds.Top, -fuv, 0, fuv * periodicBounds.Right);
                    }
                    else
                    {
                        throw new ApplicationException("the pole must be on the border of the bounds");
                    }
                    done = true;
                }
                if (!done)
                {
                    double[] sv = periodicSurface.GetVSingularities();
                    if (sv != null && sv.Length == 1)
                    {   // the "period" to be resolved is in u
                        hasPole = true;
                        if (Math.Abs(sv[0] - periodicBounds.Bottom) < periodicBounds.Height * 1e-6)
                        {                                                      // we have to map the u interval of the periodic surface onto [0..pi/2] and the v interval onto [0..1]
                            double fvu = Math.PI / 2.0 / periodicBounds.Width; // tested: ok
                            double fuv = 1.0 / periodicBounds.Height;
                            toNonPeriodicBounds = new ModOp2D(-fvu, 0, fvu * periodicBounds.Right, 0, fuv, -fuv * periodicBounds.Bottom);
                        }
                        else if (Math.Abs(sv[0] - periodicBounds.Top) < periodicBounds.Height * 1e-6)
                        {
                            double fvu = Math.PI / 2.0 / periodicBounds.Width; // tested: ok
                            double fuv = 1.0 / periodicBounds.Height;
                            toNonPeriodicBounds = new ModOp2D(fvu, 0, -fvu * periodicBounds.Left, 0, -fuv, fuv * periodicBounds.Top);
                        }
                        else
                        {
                            throw new ApplicationException("the pole must be on the border of the bounds");
                        }
                        done = true;
                    }
                }
                if (!done)
                {
                    throw new ApplicationException("there must be a single pole on the border of the bounds");
                }
            }
            toPeriodicBounds = toNonPeriodicBounds.GetInverse();
#if DEBUG
            //GeoObjectList dbg = this.DebugGrid;
            //GeoObjectList dbgp = (this.periodicSurface as ISurfaceImpl).DebugGrid;
#endif
        }
Example #5
0
        public static Ellipse2D FromPoints(IEnumerable <GeoPoint2D> points)
        {
            GeoPoint2D[] pnts = null;
            if (points is GeoPoint2D[] a)
            {
                pnts = a;
            }
            else if (points is List <GeoPoint2D> l)
            {
                pnts = l.ToArray();
            }
            else
            {
                List <GeoPoint2D> lp = new List <GeoPoint2D>();
                foreach (GeoPoint2D point2D in points)
                {
                    lp.Add(point2D);
                }
                pnts = lp.ToArray();
            }
            Vector <double> observedX = new DenseVector(pnts.Length + 1); // there is no need to set values
            Vector <double> observedY = new DenseVector(pnts.Length + 1); // this is the data we want to achieve, namely 1.0, points on the unit circle distance to origin

            for (int i = 0; i < observedY.Count; i++)
            {
                observedY[i] = 1;
            }
            observedY[pnts.Length] = 0; // the scalar product of minor and major axis
            LevenbergMarquardtMinimizer lm  = new LevenbergMarquardtMinimizer(gradientTolerance: 1e-12, maximumIterations: 20);
            IObjectiveModel             iom = ObjectiveFunction.NonlinearModel(
                new Func <Vector <double>, Vector <double>, Vector <double> >(delegate(Vector <double> vd, Vector <double> ox) // function
            {
                // parameters: the homogeneous matrix that projects the ellipse to the unit circle
                ModOp2D m       = new ModOp2D(vd[0], vd[1], vd[2], vd[3], vd[4], vd[5]);
                DenseVector res = new DenseVector(pnts.Length + 1);
                for (int i = 0; i < pnts.Length; i++)
                {
                    GeoPoint2D pp = m * pnts[i];
                    res[i]        = pp.x * pp.x + pp.y * pp.y;
                }
                res[pnts.Length] = m[0, 0] * m[0, 1] + m[1, 0] * m[1, 1];     // the axis should be perpendicular
#if DEBUG
                double err = 0.0;
                for (int i = 0; i < pnts.Length; i++)
                {
                    err += (res[i] - 1) * (res[i] - 1);
                }
                err += res[pnts.Length] * res[pnts.Length];
#endif
                return(res);
            }),
                new Func <Vector <double>, Vector <double>, Matrix <double> >(delegate(Vector <double> vd, Vector <double> ox) // derivatives
            {
                // parameters: the homogeneous matrix that projects the ellipse to the unit circle
                ModOp2D m = new ModOp2D(vd[0], vd[1], vd[2], vd[3], vd[4], vd[5]);
                var prime = new DenseMatrix(pnts.Length + 1, 6);
                for (int i = 0; i < pnts.Length; i++)
                {
                    GeoPoint2D pp = m * pnts[i];
                    prime[i, 0]   = 2 * pnts[i].x * pp.x;
                    prime[i, 1]   = 2 * pnts[i].y * pp.x;
                    prime[i, 2]   = 2 * pp.x;
                    prime[i, 3]   = 2 * pnts[i].x * pp.y;
                    prime[i, 4]   = 2 * pnts[i].y * pp.y;
                    prime[i, 5]   = 2 * pp.y;
                }
                prime[pnts.Length, 0] = m[0, 1];
                prime[pnts.Length, 1] = m[0, 0];
                prime[pnts.Length, 2] = 0;
                prime[pnts.Length, 3] = m[1, 1];
                prime[pnts.Length, 4] = m[1, 0];
                prime[pnts.Length, 5] = 0;
                return(prime);
            }), observedX, observedY);

            BoundingRect ext = new BoundingRect(pnts);
            NonlinearMinimizationResult mres = lm.FindMinimum(iom, new DenseVector(new double[] { 2.0 / ext.Width, 0, -ext.GetCenter().x, 0, 2.0 / ext.Height, -ext.GetCenter().y }));

            if (mres.ReasonForExit == ExitCondition.Converged || mres.ReasonForExit == ExitCondition.RelativeGradient)
            {
                Vector <double> vd = mres.MinimizingPoint;
                ModOp2D         m  = new ModOp2D(vd[0], vd[1], vd[2], vd[3], vd[4], vd[5]);
                m = m.GetInverse();
                return(new Ellipse2D(m * GeoPoint2D.Origin, m * GeoVector2D.XAxis, m * GeoVector2D.YAxis));
            }
            else
            {
                return(null);
            }
        }