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 }
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(); }
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)); }
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 }
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); } }