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; } }
/// <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; } } } }