/// <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 ); }
private (Mesh3, List <List <MWPoint3D> >) meshWall(Shell wall, List <List <MWPoint3D> > existingPts = null) { // create mesh using Triangle.NET library Shell w = wall.Clone(); // pre addition of points on the contours List <MWPoint3D> refinedPts = new List <MWPoint3D>(); for (int i = 0; i < w.Points.Count; i++) { int k = i == w.Points.Count - 1 ? 0 : i + 1; MWPoint3D p0 = w.Points[i]; MWPoint3D p1 = w.Points[k]; MWVector3D vec = new MWVector3D(p1.X - p0.X, p1.Y - p0.Y, p1.Z - p0.Z); vec = vec.Normalised(); double dist = Points.Distance3D(p0, p1); int n = Convert.ToInt32(dist / 0.75) + 1; double inc = dist / n; refinedPts.Add(p0); for (int j = 1; j < n; j++) { MWPoint3D ptAdded = new MWPoint3D(p0.X + j * vec.X * inc, p0.Y + j * vec.Y * inc, p0.Z + j * vec.Z * inc); refinedPts.Add(ptAdded); } } w.Points = refinedPts; if (existingPts != null) { List <MWPoint3D> exPts = existingPts.SelectMany(l => l).ToList(); for (int i = 0; i < exPts.Count; i++) { for (int j = 0; j < w.Points.Count; j++) { int k = j == w.Points.Count - 1 ? 0 : j + 1; if (PointIsOnLine(w.Points[j], w.Points[k], exPts[i])) { w.Points.Insert(k, exPts[i]); j = 0; } } } } Polygon pol = new Polygon(); var res = NormalizeShell(w); var vertices = res.Item1; pol.Add(new Contour(res.Item1)); for (int i = 0; i < vertices.Count; i++) { int k = i == res.Item1.Count - 1 ? 0 : i + 1; if (Math.Sqrt(Math.Pow(vertices[i].X - vertices[k].X, 2) + Math.Pow(vertices[i].Y - vertices[k].Y, 2)) < 0.15) { pol.Add(new Segment(vertices[i], vertices[k]), false); } } GeoTransform transform = res.Item2; double maxL = getMaxDim(w); double maxarea = 0.1 / maxL; Configuration config = new Configuration(); QualityOptions qo = new QualityOptions() { MinimumAngle = 20, MaximumArea = maxarea, }; Mesh MyMesh = (new GenericMesher()).Triangulate(pol, qo) as Mesh; List <Point3> meshPts = deNormalizeMesh(MyMesh.Vertices, wall, transform); // extracting the contour edges for future wall and slab meshing double xmax = MyMesh.Vertices.Max(p => p.X); double xmin = MyMesh.Vertices.Min(p => p.X); double ymax = MyMesh.Vertices.Max(p => p.Y); double ymin = MyMesh.Vertices.Min(p => p.Y); List <List <int> > edgesPtsIdx = MyMesh.Edges.Select(e => new List <int>() { MyMesh.Vertices.ToList().IndexOf(MyMesh.Vertices.Single(p => p.ID == e.P0)), MyMesh.Vertices.ToList().IndexOf(MyMesh.Vertices.Single(p => p.ID == e.P1)) }).ToList(); List <Edge> edges = MyMesh.Edges.ToList(); List <List <MWPoint3D> > TBEdges = new List <List <MWPoint3D> >(); List <Vertex> lv = MyMesh.Vertices.ToList(); for (int i = 0; i < edges.Count; i++) { bool b1 = lv[edgesPtsIdx[i][0]].X == xmin && lv[edgesPtsIdx[i][1]].X == xmin; bool b2 = lv[edgesPtsIdx[i][0]].X == xmax && lv[edgesPtsIdx[i][1]].X == xmax; bool b3 = lv[edgesPtsIdx[i][0]].Y == ymin && lv[edgesPtsIdx[i][1]].Y == ymin; bool b4 = lv[edgesPtsIdx[i][0]].Y == ymax && lv[edgesPtsIdx[i][1]].Y == ymax; if (b1 || b2 || b3 || b4) { TBEdges.Add(new List <MWPoint3D>() { new MWPoint3D(meshPts[edgesPtsIdx[i][0]].X, meshPts[edgesPtsIdx[i][0]].Y, meshPts[edgesPtsIdx[i][0]].Z), new MWPoint3D(meshPts[edgesPtsIdx[i][1]].X, meshPts[edgesPtsIdx[i][1]].Y, meshPts[edgesPtsIdx[i][1]].Z) }); } } return(new Mesh3(meshPts, MyMesh.Triangles.Select(t => new Face3(MyMesh.Vertices.ToList().IndexOf(t.GetVertex(0)), MyMesh.Vertices.ToList().IndexOf(t.GetVertex(1)), MyMesh.Vertices.ToList().IndexOf(t.GetVertex(2)))).ToList()), TBEdges); }