/// <summary> /// Bestimmt den geometrischen Fehler des angegebenen Vertex in Bezug auf die /// Fehlerquadrik Q. /// </summary> /// <param name="v"> /// Der Vertex, dessen geometrischer Fehler bestimmt werden soll. /// </param> /// <param name="q"> /// Die zugrundeliegende Fehlerquadrik. /// </param> /// <returns> /// Der geometrische Fehler an der Stelle des angegebenen Vertex. /// </returns> double ComputeVertexError(Double3 v, Double4x4 q) { var h = new Double4(v, 1); //// Geometrischer Fehler Δ(v) = vᵀQv. return(Double4.Dot(q * h, h)); }
private void SelectionRequested(SelectionFrustum obj) { if (_pos == null) { return; } // The user has interactively edited the constrained sections -> propagate the information to the simulation core List <int> indices = new List <int>(); List <Double3> pos = _pos.GetList(); Double4x4 trafo = _gl.SceneGraph.AbsoluteTransformation; //trafo.Invert(); Double3 center = Double3.Zero; for (int i = 0; i < pos.Count; ++i) { double d; if (obj.IsPointInside(trafo.TransformPoint(pos[i]), out d)) { indices.Add(i); center += pos[i]; } } if (indices.Count > 0) { center /= indices.Count; SceneNode n = new SceneNode(); n.RelativeTranslation = center; CoordinateSystemSceneNode cs = new CoordinateSystemSceneNode(); //cs.RelativeTranslation = center; cs.Call <SceneNode>(m => m.Overlay = true); n.Add(cs); _gl.SceneGraph.Add(n); _sim.AddConstraint(new ConstrainedSection(cs, indices)); _sim.UpdateConstraintConfiguration(); } }
/// <summary> /// Berechnet die initialen Q-Matrizen für alle Vertices. /// </summary> /// <param name="strict"> /// true, um eine <c>InvalidOperationException</c> zu werfen, falls ein /// degeneriertes Face entdeckt wird. /// </param> /// <returns> /// Eine Map der initialen Q-Matrizen. /// </returns> /// <exception cref="InvalidOperationException"> /// Es wurde ein degeneriertes Face gefunden, dessen Vertices kollinear sind. /// </exception> Dictionary <int, Double4x4> ComputeInitialQForEachVertex(bool strict) { var q = new Dictionary <int, Double4x4>(); // Kp Matrix für jede Ebene, d.h. jede Facette bestimmen. var kp = ComputeKpForEachPlane(strict); // Q Matrix für jeden Vertex mit 0 initialisieren. for (int i = 0; i < vertices.Count; i++) { q[i] = new Double4x4(); } // Q ist die Summe aller Kp Matrizen der inzidenten Facetten jedes Vertex. for (int c = 0; c < faces.Count; c++) { var f = faces[c]; for (int i = 0; i < 3; i++) { q[f[i]] = q[f[i]] + kp[c]; } } return(q); }
private void GLReady() { // Now OpenGL is ready to handle draw calls // Initialize the scene _gl.BackColor = Color.FromArgb(250, 250, 250); _gl.SceneGraph.Add(new CoordinateSystemGeometryScreenFixed()); _gl.InputHandler.MouseMove += InputHandler_MouseMove; _pointSelectionHandler = new PointSelectionHandler(_gl.InputHandler, _gl.SceneGraph, _gl.Camera); _pointSelectionHandler.SelectionRequested += SelectionRequested; _selectionHandler = new SelectionHandler(_gl.SceneGraph, _gl.InputHandler); _shiftingHandler = new ShiftingHandler(_gl.InputHandler, _gl.Camera, _selectionHandler, true); _selectionHandler.MultiSelect = false; _gl.InputHandler.RotationMatrix = Double4x4.RotationX(0.05 * Math.PI) * Double4x4.RotationY(-0.1 * Math.PI); _selectionHandler.Validator = delegate(PickingResult r) { return(r.Node is SelectableSceneNode); }; }
/// <summary> /// Bestimmt die Kosten für die Kontraktion der angegebenen Vertices. /// </summary> /// <param name="s"> /// Der erste Vertex des Paares. /// </param> /// <param name="t"> /// Der zweite Vertex des Paares. /// </param> /// <returns> /// Eine Instanz der Pair-Klasse. /// </returns> Pair ComputeMinimumCostPair(int s, int t) { Double3 target; double cost; var q = Q[s] + Q[t]; // Siehe [Gar97], Abschnitt 4 ("Approximating Error With Quadrics"). var m = new Double4x4() { M11 = q.M11, M12 = q.M12, M13 = q.M13, M14 = q.M14, M21 = q.M12, M22 = q.M22, M23 = q.M23, M24 = q.M24, M31 = q.M13, M32 = q.M23, M33 = q.M33, M34 = q.M34, M41 = 0, M42 = 0, M43 = 0, M44 = 1 }; // Wenn m invertierbar ist, lässt sich die optimale Position bestimmen. // if (m.Determinant != 0) { if (Math.Abs(m.Determinant) > 1e-10) { // Determinante ist ungleich 0 für invertierbare Matrizen. var inv = m.Inverted(); // Matrix4d.Invert(m); target = new Double3(inv.M14, inv.M24, inv.M34); cost = ComputeVertexError(target, q); } else { // } else { // Ansonsten den besten Wert aus Position von Vertex 1, Vertex 2 und // Mittelpunkt wählen. var v1 = vertices[s]; var v2 = vertices[t]; var mp = new Double3() { X = (v1.X + v2.X) / 2, Y = (v1.Y + v2.Y) / 2, Z = (v1.Z + v2.Z) / 2 }; var candidates = new[] { new { cost = ComputeVertexError(v1, q), target = v1 }, new { cost = ComputeVertexError(v2, q), target = v2 }, new { cost = ComputeVertexError(mp, q), target = mp } }; var best = (from p in candidates orderby p.cost select p).First(); target = best.target; cost = best.cost; } return(new Pair(s, t, target, cost)); }
/// <summary> /// Berechnet die Kp-Matrix für die Ebenen aller Facetten. /// </summary> /// <param name="strict"> /// true, um eine <c>InvalidOperationException</c> zu werfen, falls ein /// degeneriertes Face entdeckt wird. /// </param> /// <returns> /// Eine Liste von Kp-Matrizen. /// </returns> /// <exception cref="InvalidOperationException"> /// Es wurde ein degeneriertes Face gefunden, dessen Vertices kollinear sind. /// </exception> IList <Double4x4> ComputeKpForEachPlane(bool strict) { var kp = new List <Double4x4>(); var degenerate = new List <int[]>(); foreach (var f in faces) { var points = new[] { vertices[f[0]], vertices[f[1]], vertices[f[2]] }; // Ebene aus den 3 Ortsvektoren konstruieren. var dir1 = points[1] - points[0]; var dir2 = points[2] - points[0]; var n = Double3.Cross(dir1, dir2); // Wenn das Kreuzprodukt der Nullvektor ist, sind die Richtungsvektoren // kollinear, d.h. die Vertices liegen auf einer Geraden und die Facette // ist degeneriert. if (n == Double3.Zero) { degenerate.Add(f); if (strict) { var msg = new StringBuilder() .AppendFormat("Encountered degenerate face ({0} {1} {2})", f[0], f[1], f[2]) .AppendLine() .AppendFormat("Vertex 1: {0}\n", points[0]) .AppendFormat("Vertex 2: {0}\n", points[1]) .AppendFormat("Vertex 3: {0}\n", points[2]) .ToString(); throw new InvalidOperationException(msg); } } else { n.Normalize(); var a = n.X; var b = n.Y; var c = n.Z; var d = -Double3.Dot(n, points[0]); // Siehe [Gar97], Abschnitt 5 ("Deriving Error Quadrics"). var m = new Double4x4() { M11 = a * a, M12 = a * b, M13 = a * c, M14 = a * d, M21 = a * b, M22 = b * b, M23 = b * c, M24 = b * d, M31 = a * c, M32 = b * c, M33 = c * c, M34 = c * d, M41 = a * d, M42 = b * d, M43 = c * d, M44 = d * d }; kp.Add(m); } } if (degenerate.Count > 0) { System.Diagnostics.Debug.WriteLine("Warning: {0} degenerate faces found.", degenerate.Count); } foreach (var d in degenerate) { faces.Remove(d); } return(kp); }
private void MouseMove(System.Drawing.Point pt, Double2 xy, MouseKey buttons) { if (buttons == MouseKey.Left && enabled) { if (shifting && !lockPositions) { double zoomNormalizedScreenHeight = camera.ZoomFactor; Double2 offset = (xy - lastPos); offset.X *= zoomNormalizedScreenHeight * camera.AspectRatio; offset.Y *= zoomNormalizedScreenHeight; Double3 o = camera.Up * offset.Y + camera.Right * offset.X; for (int i = 0; i < selectionHandler.Count; ++i) { SelectableSceneNode node = selectionHandler[i]; Double4x4 m = node.AbsoluteTransformation; m.ClearTranslation(); Double4x4 mInv = m; mInv.Invert(); Double4x4 translation = (mInv * Double4x4.CreateTranslation(o) * m); if (!xDirectionEnabled) { translation.M14 = 0; } if (!yDirectionEnabled) { translation.M24 = 0; } if (!zDirectionEnabled) { translation.M34 = 0; } node.RelativeTransformation = translation * node.RelativeTransformation; OnNodeChanged(node); } lastPos = xy; } else if (directionEditingEnabled) { for (int i = 0; i < selectionHandler.Count; ++i) { IInteractiveDirectionSceneNode n = selectionHandler[i] as IInteractiveDirectionSceneNode; //object test = selectionHandler[i]; if (n != null) { if (rotateAroundViewDirectionOnly) { Double3 dir = selectionHandler[i].AbsoluteTransformation.Inverted().TransformDirection(camera.LookAt).Normalized(); n.SetEndInPlane(xy, camera, dir); } else { n.SetEnd(xy, camera); } OnNodeChanged(selectionHandler[i]); } } } if (selectionHandler.Count > 0) { OnPositionChanged(); } } }