// 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); } }
} // we assume the section coordinates are centered on the beam neutral fiber and already oriented public Beam(MWPoint3D start, MWPoint3D end, List <MWPoint2D> secPts) { Start = start; End = end; Section = secPts; }
public static List <Point3> deNormalizeMesh(ICollection <Vertex> lv, Shell s, GeoTransform t) { MWPoint3D p0 = 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 - p0.X, p.Y - p0.Y, p.Z - p0.Z)).ToList(); //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 (v,w) defining the plan of the shell and a normal n //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(); //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); // return new MWPoint2D(x, y); //}).ToList(); //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(t.Xmax.X - t.Xmin.X, t.Xmax.Y - t.Xmin.Y); // Math.Max(x1 - x0, y1 - y0); // from normalized 2D to non-normalized 2D List <MWPoint2D> dPoints = lv.Select(p => new MWPoint2D(t.Xmin.X + l * p.X, t.Xmin.Y + l * p.Y)).ToList(); if (dPoints.Any(p => double.IsNaN(p.X))) { Console.WriteLine("NaN"); } //Matrix<double> A = 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 }); Matrix <double> Ainv = t.P.Inverse(); p0 = t.X0; // s.Points[0]; List <Point3> points3d = dPoints.Select(p => { Vector <double> v2D = Vector <double> .Build.DenseOfArray(new[] { p.X, p.Y, 0.0 }); Vector <double> v3D = Ainv.Multiply(v2D); return(new Point3(p0.X + v3D[0], p0.Y + v3D[1], p0.Z + v3D[2])); }).ToList(); return(points3d); }
/// <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); }
public static (List <Cluster>, List <MWPoint3D>) KMeans(List <Column> cols, int Nc0) { // data //List<ClusterLoad> data = cols.SelectMany(c => c.Loads.Select(l => new ClusterLoad(new MWPoint3D(l.MEdx, l.MEdy, l.P), c, "C"+c.Name + " - " + l.Name))).ToList(); int Nc = Math.Min(cols.Count, Nc0); // columns are clustered according to their mean load List <ClusterLoad> loadAvg = cols.Select(c => GetAverageLoad(c)).ToList(); // means and cluster initializations List <MWPoint3D> means = new List <MWPoint3D>(); List <Cluster> clusters = new List <Cluster>(); Random r = new Random(); List <ClusterLoad> dataTemp = loadAvg.Select(d => d.Clone()).ToList(); for (int i = 0; i < Nc; i++) { int n = (int)Math.Truncate(dataTemp.Count * r.NextDouble()); means.Add(dataTemp[n].Load); dataTemp.RemoveAt(n); clusters.Add(new Cluster()); } // assignement initialization foreach (var p in loadAvg) { List <double> distances = new List <double>(); for (int i = 0; i < Nc; i++) { distances.Add(Points.Distance3D(p.Load, means[i])); } int imin = distances.IndexOf(distances.Min()); clusters[imin].Loads.Add(p); } int moves = 1; while (moves > 0) { // means update for (int i = 0; i < Nc; i++) { double x = clusters[i].Loads.Sum(p => p.Load.X) / clusters[i].Loads.Count; double y = clusters[i].Loads.Sum(p => p.Load.Y) / clusters[i].Loads.Count; double z = clusters[i].Loads.Sum(p => p.Load.Z) / clusters[i].Loads.Count; means[i] = new MWPoint3D(x, y, z); // particular case where a cluster has no element if (Double.IsNaN(means[i].X)) { means[i] = new MWPoint3D(0, 0, 0); } } // assignment update moves = 0; List <Cluster> clustersTemp = new List <Cluster>(); for (int i = 0; i < Nc; i++) { clustersTemp.Add(new Cluster()); } for (int i = 0; i < Nc; i++) { for (int k = 0; k < clusters[i].Loads.Count; k++) { List <double> distances = new List <double>(); for (int j = 0; j < Nc; j++) { distances.Add(Points.Distance3D(clusters[i].Loads[k].Load, means[j])); } int imin = distances.IndexOf(distances.Min()); if (imin != i) { clustersTemp[imin].Loads.Add(clusters[i].Loads[k]); moves++; } else { clustersTemp[i].Loads.Add(clusters[i].Loads[k]); } } } for (int i = 0; i < Nc; i++) { clusters[i] = clustersTemp[i]; } } // Distribute columns load into clusters List <Cluster> clustersOut = clusters.Select(c => new Cluster() { Loads = c.Loads.SelectMany( cl => cols.First(col => col.Name == cl.ParentColumnName).Loads.Select( l => new ClusterLoad(new MWPoint3D(l.MEdx, l.MEdy, l.P), cl.ParentColumnName, cl.ParentColumnName + " - " + l.Name))).ToList() }).ToList(); if (!clustersOut.All(c => c.Loads.Count > 0)) { return(KMeans(cols, Nc)); } else { return(clustersOut, means); } }
public ClusterLoad(MWPoint3D load, string colName, string name) { Load = load; ParentColumnName = colName; Name = name; }
public static List <List <MWPoint3D> > KMeans(List <MWPoint3D> data, int Nc) { // data normalization double maxX = data.Max(p => p.X); double maxY = data.Max(p => p.Y); double maxZ = data.Max(p => p.Z); List <MWPoint3D> dataN = data.Select(p => p = new MWPoint3D(p.X / maxX, p.Y / maxY, p.Z / maxZ)).ToList(); // means and cluster initializations List <MWPoint3D> means = new List <MWPoint3D>(); List <List <MWPoint3D> > clusters = new List <List <MWPoint3D> >(); Random r = new Random(); for (int i = 0; i < Nc; i++) { int n = (int)Math.Truncate(data.Count * r.NextDouble()); means.Add(dataN[n]); clusters.Add(new List <MWPoint3D>()); } // assignement initialization foreach (var p in dataN) { List <double> distances = new List <double>(); for (int i = 0; i < Nc; i++) { distances.Add(Points.Distance3D(p, means[i])); } int imin = distances.IndexOf(distances.Min()); clusters[imin].Add(p); } int moves = 1; while (moves > 0) { // means update for (int i = 0; i < Nc; i++) { double x = clusters[i].Sum(p => p.X) / clusters[i].Count; double y = clusters[i].Sum(p => p.Y) / clusters[i].Count; double z = clusters[i].Sum(p => p.Z) / clusters[i].Count; means[i] = new MWPoint3D(x, y, z); } // assignment update moves = 0; List <List <MWPoint3D> > clustersTemp = new List <List <MWPoint3D> >(); for (int i = 0; i < Nc; i++) { clustersTemp.Add(new List <MWPoint3D>()); } for (int i = 0; i < Nc; i++) { for (int k = 0; k < clusters[i].Count; k++) { List <double> distances = new List <double>(); for (int j = 0; j < Nc; j++) { distances.Add(Points.Distance3D(clusters[i][k], means[j])); } int imin = distances.IndexOf(distances.Min()); if (imin != i) { clustersTemp[imin].Add(clusters[i][k]); moves++; } else { clustersTemp[i].Add(clusters[i][k]); } } } for (int i = 0; i < Nc; i++) { clusters[i] = clustersTemp[i]; } } return(clusters); }