/// <summary> /// Takes two points, one of which is in the volume and one of which isn't. /// /// Finds the distance along the segment a...b that intersects the boundary of the volume. /// /// Note: this assumes that there is only one such intersection! If this is not the case, use a finer mesh. /// </summary> public static Vector3 FindBoundary(Vector3 a, Vector3 b, IVolume volume) { Debug.Assert(volume.Contains(a) != volume.Contains(b)); bool contains = volume.Contains(a); Vector3 v1 = a, v2 = b; for (int i = 0; i < 10; i++) { Vector3 mid = (v1+v2)/2; if (contains == volume.Contains(mid)) { v1 = mid; } else { v2 = mid; } } return (v1 + v2) / 2; }
public IVolume AddPlan(IntPoint[] points, IVolume abovePlan = null, float scale = 100) { IVolume output = AddPlan(NewPlan(), abovePlan); int pointCount = points.Length; Vector3 goPos = transformposition; Quaternion goInvRot = Quaternion.Inverse(transformrotation); for (int p = 0; p < pointCount; p++) { Vector3 v3 = goInvRot * (new Vector3(points[p].X / scale, 0, points[p].Y / scale) - goPos); Vector2Int v2Int = new Vector2Int(v3.x, v3.z); if (output.Contains(v2Int)) { continue; } output.AddPoint(v2Int); } return(output); }
public static void Split(Mesh input, IVolume volume, out Mesh output, out bool[] trisInside) { /** * * for triangle in input * if triangle is entirely inside or outside * add to corresponding mesh * else split triangle into 4 pieces. * three go in one mesh, one goes into the other * * Splitting a triangle, Before: * * * vA * / \ * boundary --- /---\ --- * / \ * vB1 *-------* vB2 * * * After: * * * vA * vMid1 / \ vMid2 * boundary --- *---* --- * / \ / \ * vB1 *---*---* vB2 * vMidB * **/ int np = input.points.Length, nt = input.triangles.Length; List<Vector3> points = input.points.ToList(); List<Vector3> norms = input.normals.ToList(); List<Mesh.Triangle> tris = new List<Mesh.Triangle>(); List<bool> trisIn = new List<bool>(); for(int i = 0; i < nt; i++){ var tri = input.triangles[i]; Vector3 vA = input.points[tri.vertexA]; Vector3 vB = input.points[tri.vertexB]; Vector3 vC = input.points[tri.vertexC]; int ncontains = (volume.Contains(vA) ? 1 : 0) + (volume.Contains(vB) ? 1 : 0) + (volume.Contains(vC) ? 1 : 0); if (ncontains==3) { tris.Add(tri); trisIn.Add(true); } else if (ncontains==0){ tris.Add(tri); trisIn.Add(false); } else { // see comment above for explanation Debug.Assert(ncontains == 1 || ncontains == 2); bool containsA = (ncontains==1); int ixA, ixB1, ixB2; if (volume.Contains(vA) == containsA) { ixA = tri.vertexA; ixB1 = tri.vertexB; ixB2 = tri.vertexC; } else if (volume.Contains(vB) == containsA) { ixA = tri.vertexB; ixB1 = tri.vertexA; ixB2 = tri.vertexC; } else { Debug.Assert(volume.Contains(vC) == containsA); ixA = tri.vertexC; ixB1 = tri.vertexA; ixB2 = tri.vertexB; } Vector3 vAO = input.points[ixA]; Vector3 vB1 = input.points[ixB1]; Vector3 vB2 = input.points[ixB2]; Vector3 vMid1 = FindBoundary(vAO, vB1, volume); Vector3 vMid2 = FindBoundary(vAO, vB2, volume); Vector3 vMidB = input.points[ixB1]*0.5f + input.points[ixB2]*0.5f; points.Add(vMid1); points.Add(vMid2); points.Add(vMidB); float b1 = (vMid1 - vAO).Length / ((vB1 - vAO).Length + float.Epsilon); float b2 = (vMid2 - vAO).Length / ((vB2 - vAO).Length + float.Epsilon); Debug.Assert(0 <= b1 && b1 <= 1 && 0 <= b2 && b2 <= 1); Vector3 nMid1 = input.normals[ixA] * (1 - b1) + input.normals[ixB1] * b1; Vector3 nMid2 = input.normals[ixA] * (1 - b2) + input.normals[ixB2] * b2; Vector3 nMidB = input.normals[ixB1] * 0.5f + input.normals[ixB2] * 0.5f; nMid1.Normalize(); nMid2.Normalize(); nMidB.Normalize(); norms.Add(nMid1); norms.Add(nMid2); norms.Add(nMidB); //norms.Add(input.normals[ixA]); norms.Add(input.normals[ixA]); norms.Add(input.normals[ixA]); var tri1 = new Mesh.Triangle(ixA, points.Count - 3, points.Count - 2); var tri2 = new Mesh.Triangle(ixB1, points.Count - 3, points.Count - 1); var tri3 = new Mesh.Triangle(points.Count - 3, points.Count - 2, points.Count - 1); var tri4 = new Mesh.Triangle(ixB2, points.Count - 2, points.Count - 1); tri1.normal = tri2.normal = tri3.normal = tri4.normal = tri.normal; tris.Add(tri1); tris.Add(tri2); tris.Add(tri3); tris.Add(tri4); trisIn.Add(containsA); trisIn.Add(!containsA); trisIn.Add(!containsA); trisIn.Add(!containsA); } } // done Logger.info("split mesh, started with " + nt + " tris, added " + (tris.Count-nt)); Debug.Assert(points.Count==norms.Count); output = new Mesh(points.ToArray(), norms.ToArray(), tris.ToArray()); trisInside = trisIn.ToArray(); }