// Returns true of the points p0 is on the closed line formed by p1 and p2 // returns false if p0 equals p1 or p2 private bool PointIsOnLine(MWPoint3D p1, MWPoint3D p2, MWPoint3D p0) { double tol = 1e-5; if (Math.Abs(p0.X - p1.X) < tol && Math.Abs(p0.Y - p1.Y) < tol && Math.Abs(p0.Z - p1.Z) < tol) { return(false); } if (Math.Abs(p0.X - p2.X) < tol && Math.Abs(p0.Y - p2.Y) < tol && Math.Abs(p0.Z - p2.Z) < tol) { return(false); } MWVector3D v1 = new MWVector3D(p0.X - p1.X, p0.Y - p1.Y, p0.Z - p1.Z); MWVector3D v2 = new MWVector3D(p0.X - p2.X, p0.Y - p2.Y, p0.Z - p2.Z); MWVector3D vp = Vectors3D.VectorialProduct(v1, v2); bool aligned = Math.Sqrt(vp.X * vp.X + vp.Y * vp.Y + vp.Z * vp.Z) < 1e-4; if (aligned) { return(Points.Distance3D(p0, p1) + Points.Distance3D(p0, p2) - Points.Distance3D(p1, p2) < 1e-3); } else { return(false); } }
/// <summary> /// Normalizes the points coordinates in the plane defined by the shell, and returns the holes and wall segments coordinates /// in this new reference system /// </summary> /// <param name="s"></param> /// <param name="segments"></param> /// <returns></returns> public static (List <Vertex>, GeoTransform) NormalizeShell(Shell s) { MWPoint3D X0 = s.Points[0]; // we choose a point p0 and make sure the origin is part of the plane of the shell List <MWPoint3D> cPoints = s.Points.Select(p => new MWPoint3D(p.X - X0.X, p.Y - X0.Y, p.Z - X0.Z)).ToList(); List <List <MWPoint3D> > cHolesPoints = s.Holes.Select(lp => lp.Select(p => new MWPoint3D(p.X - X0.X, p.Y - X0.Y, p.Z - X0.Z)).ToList()).ToList(); List <List <MWPoint3D> > cSegPoints = s.IncludedSegments.Select(lp => lp.Select(p => new MWPoint3D(p.X - X0.X, p.Y - X0.Y, p.Z - X0.Z)).ToList()).ToList(); MWPoint3D p0 = new MWPoint3D(0, 0, 0); // we look for 2 points such that p0, p1 and p2 are not aligned MWPoint3D p1 = cPoints[1]; MWPoint3D p2 = cPoints[2]; for (int i = 2; i < cPoints.Count; i++) { p2 = cPoints[i]; double dp = Math.Abs((p2.X - p0.X) * (p1.X - p0.X) + (p2.Y - p0.Y) * (p1.Y - p0.Y) + (p2.Z - p0.Z) * (p1.Z - p0.Z)); if (dp < Points.Distance3D(p0, p1) * Points.Distance3D(p0, p2) - 1e-4) { break; } } // we extract two normal vectors defining the plan of the shell MWVector3D v = new MWVector3D(p1.X - p0.X, p1.Y - p0.Y, p1.Z - p0.Z); v = v.Normalised(); MWVector3D w0 = new MWVector3D(p2.X - p0.X, p2.Y - p0.Y, p2.Z - p0.Z); MWVector3D n = Vectors3D.VectorialProduct(v, w0); n = n.Normalised(); MWVector3D w = Vectors3D.VectorialProduct(v, n); w = w.Normalised(); Matrix <double> P = Matrix <double> .Build.DenseOfRowArrays(new[] { v.X, v.Y, v.Z }, new[] { w.X, w.Y, w.Z }, new[] { n.X, n.Y, n.Z }); List <MWPoint2D> newPts = cPoints.Select(p => { MWVector3D vp = new MWVector3D(p.X, p.Y, p.Z); double x = Vectors3D.ScalarProduct(vp, v); double y = Vectors3D.ScalarProduct(vp, w); double z = Vectors3D.ScalarProduct(vp, n); //Console.WriteLine("z = {0} (should be 0)", z); return(new MWPoint2D(x, y)); }).ToList(); //List<List<MWPoint2D>> newHolesPts = cHolesPoints.Select(lp => lp.Select(p => //{ // MWVector3D vp = new MWVector3D(p.X, p.Y, p.Z); // double x = Vectors3D.ScalarProduct(vp, v); // double y = Vectors3D.ScalarProduct(vp, w); // double z = Vectors3D.ScalarProduct(vp, n); // //Console.WriteLine("z = {0} (should be 0)", z); // return new MWPoint2D(x, y); //}).ToList()).ToList(); //List<List<MWPoint2D>> newSegPts = cSegPoints.Select(lp => lp.Select(p => //{ // MWVector3D vp = new MWVector3D(p.X, p.Y, p.Z); // double x = Vectors3D.ScalarProduct(vp, v); // double y = Vectors3D.ScalarProduct(vp, w); // double z = Vectors3D.ScalarProduct(vp, n); // //Console.WriteLine("z = {0} (should be 0)", z); // return new MWPoint2D(x, y); //}).ToList()).ToList(); if (newPts.Any(p => double.IsNaN(p.X))) { Console.WriteLine("NaN"); } double x0 = newPts.Min(p => p.X); double y0 = newPts.Min(p => p.Y); double x1 = newPts.Max(p => p.X); double y1 = newPts.Max(p => p.Y); double l = Math.Max(x1 - x0, y1 - y0); GeoTransform trans = new GeoTransform() { P = P, X0 = X0, Xmin = new MWPoint2D(x0, y0), Xmax = new MWPoint2D(x1, y1) }; return(newPts.Select(p => new Vertex((p.X - x0) / l, (p.Y - y0) / l)).ToList(), trans ); }