private void RenderGUI() { //============================================================================ // Render a visual marker to highlight the node that is being manipulated //============================================================================ if (solver.HandleNodeIndex != -1 || solver.NearestNodeIndex != -1) { CameraData camera = DynaShapeViewExtension.CameraData; Triple camOrigin = new Triple(camera.EyePosition.X, -camera.EyePosition.Z, camera.EyePosition.Y); Triple camZ = new Triple(camera.LookDirection.X, -camera.LookDirection.Z, camera.LookDirection.Y).Normalise(); Triple camY = new Triple(camera.UpDirection.X, -camera.UpDirection.Z, camera.UpDirection.Y).Normalise(); Triple camX = camZ.Cross(camY); int nodeIndex = solver.HandleNodeIndex != -1 ? solver.HandleNodeIndex : solver.NearestNodeIndex; Triple v = solver.Nodes[nodeIndex].Position - camOrigin; float screenDistance = (float)camera.NearPlaneDistance + 0.1f; v = camOrigin + v * screenDistance / v.Dot(camZ); float markerSize = 0.025f * screenDistance; Triple v1 = v + camX * markerSize; Triple v2 = v - camY * markerSize; Triple v3 = v - camX * markerSize; Triple v4 = v + camY * markerSize; lineGeometry.Positions.Add(v1.ToVector3()); lineGeometry.Positions.Add(v3.ToVector3()); lineGeometry.Positions.Add(v2.ToVector3()); lineGeometry.Positions.Add(v4.ToVector3()); markerSize *= 0.5f; v1 = v + camX * markerSize; v2 = v - camY * markerSize; v3 = v - camX * markerSize; v4 = v + camY * markerSize; lineGeometry.Positions.Add(v1.ToVector3()); lineGeometry.Positions.Add(v2.ToVector3()); lineGeometry.Positions.Add(v2.ToVector3()); lineGeometry.Positions.Add(v3.ToVector3()); lineGeometry.Positions.Add(v3.ToVector3()); lineGeometry.Positions.Add(v4.ToVector3()); lineGeometry.Positions.Add(v4.ToVector3()); lineGeometry.Positions.Add(v1.ToVector3()); int temp = lineGeometry.Indices.Count; for (int i = 0; i < 12; i++) { lineGeometry.Indices.Add(temp + i); lineGeometry.Colors.Add(Color.OrangeRed); } } }
/// <summary> /// Compute the plane that best fit a set of input points (least squared orthogonal distance) /// </summary> /// <param name="points">The input points</param> /// <param name="planeOrigin">The output plane origin</param> /// <param name="planeNormal">The output plane normal vector</param> /// <returns>0 if the input points are identical, 1 if the input points are colinear, 2 if the input points are coplanar (already on a plane), 3 otherwise</returns> public static int ComputeBestFitPlane(List <Triple> points, out Triple planeOrigin, out Triple planeNormal) { Triple centroid = Triple.Zero; for (int i = 0; i < points.Count; i++) { centroid += points[i]; } centroid /= points.Count; float[,] P = new float[points.Count, 3]; for (int i = 0; i < points.Count; i++) { P[i, 0] = points[i].X - centroid.X; P[i, 1] = points[i].Y - centroid.Y; P[i, 2] = points[i].Z - centroid.Z; } Matrix <float> covariance = Matrix <float> .Build.Dense(3, 3); for (int i = 0; i < 3; i++) { for (int j = 0; j < 3; j++) { for (int k = 0; k < points.Count; k++) { covariance[i, j] += P[k, i] * P[k, j]; } } } Evd <float> evd = covariance.Evd(); planeOrigin = centroid; if (evd.Rank == 0) // The input points are idendtical, so we just pick an arbitrary normal vector { planeNormal = Triple.BasisZ; } else if (evd.Rank == 1 ) // The input points are colinear, so we just pick an arbitrary vector perpendicular to the only eigen vector { planeNormal = new Triple(evd.EigenVectors[0, 1], evd.EigenVectors[1, 1], evd.EigenVectors[2, 1]) .GeneratePerpendicular(); } else // The normal is perpendicular to the two dominant eigen vectors { Triple e1 = new Triple(evd.EigenVectors[0, 1], evd.EigenVectors[1, 1], evd.EigenVectors[2, 1]); Triple e2 = new Triple(evd.EigenVectors[0, 2], evd.EigenVectors[1, 2], evd.EigenVectors[2, 2]); planeNormal = e2.Cross(e1).Normalise(); } return(evd.Rank); }
public void Tessellate(IRenderPackage package, TessellationParameters parameters) { for (int i = 0; i < solver.Nodes.Count; i++) { GeometryRender.DrawPoint(package, solver.Nodes[i].Position); } for (int i = 0; i < solver.GeometryBinders.Count; i++) { solver.GeometryBinders[i].DrawGraphics(package, parameters, solver.Nodes); } //======================================================================================= // Draw a cursor to highlight the node that is being manipulated by the mouse // ... the curor is 2D, so we need to draw it in the camera coordinate system, manually //======================================================================================= CameraData camera = ((HelixWatch3DViewModel)Solver.Viewport).Camera.Dispatcher.Invoke(() => Solver.Viewport.GetCameraInformation()); Triple camOrigin = new Triple(camera.EyePosition.X, -camera.EyePosition.Z, camera.EyePosition.Y); Triple camZ = new Triple(camera.LookDirection.X, -camera.LookDirection.Z, camera.LookDirection.Y).Normalise(); Triple camY = new Triple(camera.UpDirection.X, -camera.UpDirection.Z, camera.UpDirection.Y).Normalise(); Triple camX = camZ.Cross(camY); if (solver.HandleNodeIndex != -1 || solver.NearestNodeIndex != -1) { int i = solver.HandleNodeIndex != -1 ? solver.HandleNodeIndex : solver.NearestNodeIndex; Color handleColor = solver.HandleNodeIndex != -1 ? Color.OrangeRed : Color.Black; Triple v = solver.Nodes[i].Position - camOrigin; v = camOrigin + ((float)camera.NearPlaneDistance + 0.5f) * v / v.Dot(camZ); float handleSize = 0.008f; Triple v1 = v + camX * handleSize; Triple v2 = v - camY * handleSize; Triple v3 = v - camX * handleSize; Triple v4 = v + camY * handleSize; GeometryRender.DrawPolyline(package, new List <Triple> { v1, v2, v3, v4, v1 }, handleColor); handleSize = 0.015f; v1 = v + camX * handleSize; v2 = v - camY * handleSize; v3 = v - camX * handleSize; v4 = v + camY * handleSize; GeometryRender.DrawLine(package, v1, v3, handleColor); GeometryRender.DrawLine(package, v2, v4, handleColor); } }
/// <summary> /// Compute the plane that best fit a set of input points (least squared orthogonal distance) /// </summary> /// <param name="points">The input points</param> /// <param name="planeOrigin">The output plane origin</param> /// <param name="planeNormal">The output plane normal vector</param> /// <returns>0 if the input points are identical, 1 if the input points are colinear, 2 if the input points are coplanar (already on a plane), 3 otherwise</returns> //public static int ComputeBestFitPlane(List<Triple> points, out Triple planeOrigin, out Triple planeNormal) //{ // Triple centroid = Triple.Zero; // for (int i = 0; i < points.Count; i++) centroid += points[i]; // centroid /= points.Count; // float[,] P = new float[points.Count, 3]; // for (int i = 0; i < points.Count; i++) // { // P[i, 0] = points[i].X - centroid.X; // P[i, 1] = points[i].Y - centroid.Y; // P[i, 2] = points[i].Z - centroid.Z; // } // Matrix<float> covariance = Matrix<float>.Build.Dense(3, 3); // for (int i = 0; i < 3; i++) // for (int j = 0; j < 3; j++) // for (int k = 0; k < points.Count; k++) // covariance[i, j] += P[k, i] * P[k, j]; // Evd<float> evd = covariance.Evd(); // planeOrigin = centroid; // if (evd.Rank == 0) // The input points are idendtical, so we just pick an arbitrary normal vector // planeNormal = Triple.BasisZ; // else if (evd.Rank == 1 // ) // The input points are colinear, so we just pick an arbitrary vector perpendicular to the only eigen vector // planeNormal = new Triple(evd.EigenVectors[0, 1], evd.EigenVectors[1, 1], evd.EigenVectors[2, 1]) // .GeneratePerpendicular(); // else // The normal is perpendicular to the two dominant eigen vectors // { // Triple e1 = new Triple(evd.EigenVectors[0, 1], evd.EigenVectors[1, 1], evd.EigenVectors[2, 1]); // Triple e2 = new Triple(evd.EigenVectors[0, 2], evd.EigenVectors[1, 2], evd.EigenVectors[2, 2]); // planeNormal = e2.Cross(e1).Normalise(); // } // return evd.Rank; //} public static int ComputeBestFitPlane(List <Triple> points, out Triple planeOrigin, out Triple planeNormal) { Triple centroid = Triple.Zero; for (int i = 0; i < points.Count; i++) { centroid += points[i]; } centroid /= points.Count; float[,] P = new float[points.Count, 3]; for (int i = 0; i < points.Count; i++) { P[i, 0] = points[i].X - centroid.X; P[i, 1] = points[i].Y - centroid.Y; P[i, 2] = points[i].Z - centroid.Z; } Matrix3x3 covariance = new Matrix3x3(); for (int k = 0; k < points.Count; k++) { covariance.V00 += P[k, 0] * P[k, 0]; covariance.V01 += P[k, 0] * P[k, 1]; covariance.V02 += P[k, 0] * P[k, 2]; covariance.V10 += P[k, 1] * P[k, 0]; covariance.V11 += P[k, 1] * P[k, 1]; covariance.V12 += P[k, 1] * P[k, 2]; covariance.V20 += P[k, 2] * P[k, 0]; covariance.V21 += P[k, 2] * P[k, 1]; covariance.V22 += P[k, 2] * P[k, 2]; } Matrix3x3 u, v; AForge.Math.Vector3 e; covariance.SVD(out u, out e, out v); planeOrigin = centroid; Triple e1 = new Triple(u.V00, u.V10, u.V20); Triple e2 = new Triple(u.V01, u.V11, u.V21); planeNormal = e2.Cross(e1).Normalise(); return(3); }
internal int FindNearestNodeIndex(float range = 0.03f) { CameraData cameraData = DynaShapeViewExtension.CameraData; Triple camZ = new Triple( cameraData.LookDirection.X, -cameraData.LookDirection.Z, cameraData.LookDirection.Y).Normalise(); Triple camY = new Triple( cameraData.UpDirection.X, -cameraData.UpDirection.Z, cameraData.UpDirection.Y).Normalise(); Triple camX = camY.Cross(camZ).Normalise(); Triple mousePosition2D = new Triple( DynaShapeViewExtension.MouseRayDirection.Dot(camX), DynaShapeViewExtension.MouseRayDirection.Dot(camY), DynaShapeViewExtension.MouseRayDirection.Dot(camZ)); mousePosition2D /= mousePosition2D.Z; int nearestNodeIndex = -1; float minDistSquared = range * range; for (int i = 0; i < Nodes.Count; i++) { Triple v = Nodes[i].Position - DynaShapeViewExtension.MouseRayOrigin; v = new Triple(v.Dot(camX), v.Dot(camY), v.Dot(camZ)); Triple nodePosition2D = v / v.Z; float distSquared = (mousePosition2D - nodePosition2D).LengthSquared; if (distSquared < minDistSquared) { minDistSquared = distSquared; nearestNodeIndex = i; } } return(nearestNodeIndex); }
public Triple Rotate(Triple origin, Triple Axis, float angle) { Triple z = Axis.Normalise(); Triple x = z.GeneratePerpendicular().Normalise(); Triple y = z.Cross(x).Normalise(); Triple v = this - origin; float vx = x.Dot(v); float vy = y.Dot(v); float vz = z.Dot(v); float sin = (float)Math.Sin(angle); float cos = (float)Math.Cos(angle); float vx_ = cos * vx - sin * vy; float vy_ = sin * vx + cos * vy; return(origin + x * vx_ + y * vy_ + z * vz); }
internal int FindNearestNodeIndex(IRay clickRay, float range = 0.03f) { CameraData cameraData = Viewport.GetCameraInformation(); Triple camZ = new Triple(cameraData.LookDirection.X, -cameraData.LookDirection.Z, cameraData.LookDirection.Y).Normalise(); Triple camY = new Triple(cameraData.UpDirection.X, -cameraData.UpDirection.Z, cameraData.UpDirection.Y) .Normalise(); Triple camX = camY.Cross(camZ).Normalise(); Triple clickRayOrigin = new Triple(clickRay.Origin.X, clickRay.Origin.Y, clickRay.Origin.Z); Triple clickRayDirection = new Triple(clickRay.Direction.X, clickRay.Direction.Y, clickRay.Direction.Z); Triple mousePosition2D = new Triple(clickRayDirection.Dot(camX), clickRayDirection.Dot(camY), clickRayDirection.Dot(camZ)); mousePosition2D /= mousePosition2D.Z; int nearestNodeIndex = -1; float minDistSquared = range * range; for (int i = 0; i < Nodes.Count; i++) { Triple v = Nodes[i].Position - clickRayOrigin; v = new Triple(v.Dot(camX), v.Dot(camY), v.Dot(camZ)); Triple nodePosition2D = v / v.Z; float distSquared = (mousePosition2D - nodePosition2D).LengthSquared; if (distSquared < minDistSquared) { minDistSquared = distSquared; nearestNodeIndex = i; } } return(nearestNodeIndex); }