diff --git a/OpenSim/Region/Physics/OdePlugin/Meshing/Extruder.cs b/OpenSim/Region/Physics/OdePlugin/Meshing/Extruder.cs new file mode 100755 index 0000000000..497e039a58 --- /dev/null +++ b/OpenSim/Region/Physics/OdePlugin/Meshing/Extruder.cs @@ -0,0 +1,83 @@ +using System; +using System.Collections.Generic; +using System.Text; + +namespace OpenSim.Region.Physics.OdePlugin.Meshing +{ + class Extruder + { + public float startParameter; + public float stopParameter; + public Manager.PhysicsVector size; + + public Mesh Extrude(Mesh m) + { + // Currently only works for iSteps=1; + Mesh result = new Mesh(); + + Mesh workingPlus = m.Clone(); + Mesh workingMinus = m.Clone(); + + foreach (Vertex v in workingPlus.vertices) + { + if (v == null) + continue; + + v.Z = +.5f; + v.X *= size.X; + v.Y *= size.Y; + v.Z *= size.Z; + } + + foreach (Vertex v in workingMinus.vertices) + { + if (v == null) + continue; + + v.Z = -.5f; + v.X *= size.X; + v.Y *= size.Y; + v.Z *= size.Z; + } + + foreach (Triangle t in workingMinus.triangles) + { + t.invertNormal(); + } + + result.Append(workingMinus); + result.Append(workingPlus); + + int iLastNull = 0; + for (int i = 0; i < workingPlus.vertices.Count; i++) + { + int iNext = (i + 1); + + if (workingPlus.vertices[i] == null) // Can't make a simplex here + { + iLastNull = i+1; + continue; + } + + if (i == workingPlus.vertices.Count-1) // End of list + { + iNext = iLastNull; + } + + if (workingPlus.vertices[iNext] == null) // Null means wrap to begin of last segment + { + iNext = iLastNull; + } + + Triangle tSide; + tSide = new Triangle(workingPlus.vertices[i], workingMinus.vertices[i], workingPlus.vertices[iNext]); + result.Add(tSide); + + tSide = new Triangle(workingPlus.vertices[iNext], workingMinus.vertices[i], workingMinus.vertices[iNext]); + result.Add(tSide); + } + + return result; + } + } +} diff --git a/OpenSim/Region/Physics/OdePlugin/Meshing/Mesh.cs b/OpenSim/Region/Physics/OdePlugin/Meshing/Mesh.cs new file mode 100755 index 0000000000..5a51703518 --- /dev/null +++ b/OpenSim/Region/Physics/OdePlugin/Meshing/Mesh.cs @@ -0,0 +1,197 @@ +using System; +using System.IO; +using System.Collections.Generic; +using System.Text; + +using System.Runtime.InteropServices; + + +using OpenSim.Region.Physics.Manager; + +namespace OpenSim.Region.Physics.OdePlugin.Meshing +{ + public class Mesh + { + public List vertices; + public List triangles; + + public float[] normals; + + public Mesh() + { + vertices = new List(); + triangles = new List(); + } + + public Mesh Clone() + { + Mesh result = new Mesh(); + + foreach (Vertex v in vertices) + { + if (v == null) + result.vertices.Add(null); + else + result.vertices.Add(v.Clone()); + } + + foreach (Triangle t in triangles) + { + int iV1, iV2, iV3; + iV1 = this.vertices.IndexOf(t.v1); + iV2 = this.vertices.IndexOf(t.v2); + iV3 = this.vertices.IndexOf(t.v3); + + Triangle newT = new Triangle(result.vertices[iV1], result.vertices[iV2], result.vertices[iV3]); + result.Add(newT); + } + + return result; + } + + + + public void Add(Triangle triangle) + { + int i; + i = vertices.IndexOf(triangle.v1); + if (i < 0) + throw new ArgumentException("Vertex v1 not known to mesh"); + i = vertices.IndexOf(triangle.v2); + if (i < 0) + throw new ArgumentException("Vertex v2 not known to mesh"); + i = vertices.IndexOf(triangle.v3); + if (i < 0) + throw new ArgumentException("Vertex v3 not known to mesh"); + + triangles.Add(triangle); + } + + public void Add(Vertex v) + { + vertices.Add(v); + } + + public void Remove(Vertex v) + { + int i; + + // First, remove all triangles that are build on v + for (i = 0; i < triangles.Count; i++) + { + Triangle t = triangles[i]; + if (t.v1 == v || t.v2 == v || t.v3 == v) + { + triangles.RemoveAt(i); + i--; + } + } + + // Second remove v itself + vertices.Remove(v); + } + + public void RemoveTrianglesOutside(SimpleHull hull) + { + int i; + + for (i = 0; i < triangles.Count; i++) + { + Triangle t = triangles[i]; + Vertex v1 = t.v1; + Vertex v2 = t.v2; + Vertex v3 = t.v3; + PhysicsVector m = v1 + v2 + v3; + m /= 3.0f; + if (!hull.IsPointIn(new Vertex(m))) + { + triangles.RemoveAt(i); + i--; + } + } + } + + + public void Add(List lv) + { + foreach (Vertex v in lv) + { + vertices.Add(v); + } + } + + public float[] getVertexListAsFloat() + { + float[] result = new float[vertices.Count * 3]; + for (int i = 0; i < vertices.Count; i++) + { + Vertex v = vertices[i]; + if (v == null) + continue; + result[3 * i + 0] = v.X; + result[3 * i + 1] = v.Y; + result[3 * i + 2] = v.Z; + } + GCHandle.Alloc(result, GCHandleType.Pinned); + return result; + } + + public int[] getIndexListAsInt() + { + int[] result = new int[triangles.Count * 3]; + for (int i = 0; i < triangles.Count; i++) + { + Triangle t = triangles[i]; + result[3 * i + 0] = vertices.IndexOf(t.v1); + result[3 * i + 1] = vertices.IndexOf(t.v2); + result[3 * i + 2] = vertices.IndexOf(t.v3); + } + GCHandle.Alloc(result, GCHandleType.Pinned); + return result; + } + + + public void Append(Mesh newMesh) + { + foreach (Vertex v in newMesh.vertices) + vertices.Add(v); + + foreach (Triangle t in newMesh.triangles) + Add(t); + + } + + // Do a linear transformation of mesh. + public void TransformLinear(float[,] matrix, float[] offset) + { + foreach (Vertex v in vertices) + { + if (v == null) + continue; + float x, y, z; + x = v.X * matrix[0, 0] + v.Y * matrix[1, 0] + v.Z * matrix[2, 0]; + y = v.X * matrix[0, 1] + v.Y * matrix[1, 1] + v.Z * matrix[2, 1]; + z = v.X * matrix[0, 2] + v.Y * matrix[1, 2] + v.Z * matrix[2, 2]; + v.X = x + offset[0]; + v.Y = y + offset[1]; + v.Z = z + offset[2]; + } + } + + public void DumpRaw(String path, String name, String title) + { + if (path == null) + return; + String fileName = name + "_" + title + ".raw"; + String completePath = Path.Combine(path, fileName); + StreamWriter sw = new StreamWriter(completePath); + foreach (Triangle t in triangles) + { + String s = t.ToStringRaw(); + sw.WriteLine(s); + } + sw.Close(); + } + } + +} diff --git a/OpenSim/Region/Physics/OdePlugin/Meshing/SimpleHull.cs b/OpenSim/Region/Physics/OdePlugin/Meshing/SimpleHull.cs new file mode 100755 index 0000000000..2caa818c00 --- /dev/null +++ b/OpenSim/Region/Physics/OdePlugin/Meshing/SimpleHull.cs @@ -0,0 +1,363 @@ +using System; +using System.Collections.Generic; +using System.Text; + +using OpenSim.Framework.Console; + +namespace OpenSim.Region.Physics.OdePlugin.Meshing +{ + // A simple hull is a set of vertices building up to simplices that border a region + // The word simple referes to the fact, that this class assumes, that all simplices + // do not intersect + // Simple hulls can be added and subtracted. + // Vertices can be checked to lie inside a hull + // Also note, that the sequence of the vertices is important and defines if the region that + // is defined by the hull lies inside or outside the simplex chain + public class SimpleHull + { + List vertices = new List(); + List holeVertices = new List(); // Only used, when the hull is hollow + + // Adds a vertex to the end of the list + public void AddVertex(Vertex v) { + vertices.Add(v); + } + + override public String ToString() + { + String result=""; + foreach (Vertex v in vertices) + { + result += "b:" + v.ToString() + "\n"; + } + + return result; + } + + + public List getVertices() { + List newVertices = new List(); + + newVertices.AddRange(vertices); + newVertices.Add(null); + newVertices.AddRange(holeVertices); + + return newVertices; + } + + public SimpleHull Clone() + { + SimpleHull result = new SimpleHull(); + foreach (Vertex v in vertices) + { + result.AddVertex(v.Clone()); + } + + foreach (Vertex v in this.holeVertices) + { + result.holeVertices.Add(v.Clone()); + } + + return result; + } + + public bool IsPointIn(Vertex v1) + { + int iCounter=0; + List simplices=buildSimplexList(); + foreach (Simplex s in simplices) + { + // Send a ray along the positive X-Direction + // Note, that this direction must correlate with the "below" interpretation + // of handling for the special cases below + Manager.PhysicsVector intersection = s.RayIntersect(v1, new Manager.PhysicsVector(1.0f, 0.0f, 0.0f), true); + + if (intersection == null) + continue; // No intersection. Done. More tests to follow otherwise + + // Did we hit the end of a simplex? + // Then this can be one of two special cases: + // 1. we go through a border exactly at a joint + // 2. we have just marginally touched a corner + // 3. we can slide along a border + // Solution: If the other vertex is "below" the ray, we don't count it + // Thus corners pointing down are counted twice, corners pointing up are not counted + // borders are counted once + if (intersection.IsIdentical(s.v1, 0.001f)) { + if (s.v2.Y < v1.Y) + continue; + } + // Do this for the other vertex two + if (intersection.IsIdentical(s.v2, 0.001f)) { + if (s.v1.Y buildSimplexList() { + + List result = new List(); + + // Not asserted but assumed: at least three vertices + for (int i=0; i simple = buildSimplexList(); + foreach (Simplex sTest in simple) + { + Manager.PhysicsVector vvTemp = Simplex.Intersect(sTest, s, -.001f, -.001f, 0.999f, .999f); + + Vertex vTemp=null; + if (vvTemp != null) + vTemp = new Vertex(vvTemp); + + if (vTemp!=null) { + + Manager.PhysicsVector diff=(s.v1-vTemp); + float distTemp=diff.length(); + + if (bestIntersection==null || distTemp + { + public Vertex v1; + public Vertex v2; + + public Simplex(Vertex _v1, Vertex _v2) + { + v1 = _v1; + v2 = _v2; + } + + public int CompareTo(Simplex other) + { + + Vertex lv1, lv2, ov1, ov2, temp; + + lv1 = v1; + lv2 = v2; + ov1 = other.v1; + ov2 = other.v2; + + if (lv1 > lv2) + { + temp = lv1; + lv1 = lv2; + lv2 = temp; + } + + if (ov1 > ov2) + { + temp = ov1; + ov1 = ov2; + ov2 = temp; + } + + if (lv1 > ov1) + { + return 1; + } + if (lv1 < ov1) + { + return -1; + } + + if (lv2 > ov2) + { + return 1; + } + if (lv2 < ov2) + { + return -1; + } + + return 0; + } + + private static void intersectParameter(PhysicsVector p1, PhysicsVector r1, PhysicsVector p2, PhysicsVector r2, ref float lambda, ref float mu) + { + // Intersects two straights + // p1, p2, points on the straight + // r1, r2, directional vectors of the straight. Not necessarily of length 1! + // note, that l, m can be scaled such, that the range 0..1 is mapped to the area between two points, + // thus allowing to decide whether an intersection is between two points + + float r1x = r1.X; + float r1y = r1.Y; + float r2x = r2.X; + float r2y = r2.Y; + + float denom = r1y*r2x - r1x*r2y; + + float p1x = p1.X; + float p1y = p1.Y; + float p2x = p2.X; + float p2y = p2.Y; + + float z1=-p2x * r2y + p1x * r2y + (p2y - p1y) * r2x; + float z2=-p2x * r1y + p1x * r1y + (p2y - p1y) * r1x; + + if (denom == 0.0f) // Means the straights are parallel. Either no intersection or an infinite number of them + { + if (z1==0.0f) {// Means they are identical -> many, many intersections + lambda = Single.NaN; + mu = Single.NaN; + } else { + lambda = Single.PositiveInfinity; + mu = Single.PositiveInfinity; + } + return; + + } + + + + lambda = z1 / denom; + mu = z2 / denom; + + } + + + // Intersects the simplex with another one. + // the borders are used to deal with float inaccuracies + // As a rule of thumb, the borders are + // lowerBorder1 : 0.0 + // lowerBorder2 : 0.0 + // upperBorder1 : 1.0 + // upperBorder2 : 1.0 + // Set these to values near the given parameters (e.g. 0.001 instead of 1 to exclude simplex starts safely, or to -0.001 to include them safely) + public static PhysicsVector Intersect( + Simplex s1, + Simplex s2, + float lowerBorder1, + float lowerBorder2, + float upperBorder1, + float upperBorder2) + { + PhysicsVector firstSimplexDirection = s1.v2 - s1.v1; + PhysicsVector secondSimplexDirection = s2.v2 - s2.v1; + + float lambda = 0.0f; + float mu = 0.0f; + + // Give us the parameters of an intersection. This subroutine does *not* take the constraints + // (intersection must be between v1 and v2 and it must be in the positive direction of the ray) + // into account. We do that afterwards. + intersectParameter(s1.v1, firstSimplexDirection, s2.v1, secondSimplexDirection, ref lambda, ref mu); + + if (Single.IsInfinity(lambda)) // Special case. No intersection at all. directions parallel. + return null; + + if (Single.IsNaN(lambda)) // Special case. many, many intersections. + return null; + + if (lambda > upperBorder1) // We're behind v2 + return null; + + if (lambda < lowerBorder1) + return null; + + if (mu < lowerBorder2) // outside simplex 2 + return null; + + if (mu > upperBorder2) // outside simplex 2 + return null; + + return s1.v1 + lambda * firstSimplexDirection; + + } + + // Intersects the simplex with a ray. The ray is defined as all p=origin + lambda*direction + // where lambda >= 0 + public PhysicsVector RayIntersect(Vertex origin, PhysicsVector direction, bool bEndsIncluded) + { + PhysicsVector simplexDirection = v2 - v1; + + float lambda = 0.0f; + float mu = 0.0f; + + // Give us the parameters of an intersection. This subroutine does *not* take the constraints + // (intersection must be between v1 and v2 and it must be in the positive direction of the ray) + // into account. We do that afterwards. + intersectParameter(v1, simplexDirection, origin, direction, ref lambda, ref mu); + + if (Single.IsInfinity(lambda)) // Special case. No intersection at all. directions parallel. + return null; + + if (Single.IsNaN(lambda)) // Special case. many, many intersections. + return null; + + if (mu < 0.0) // We're on the wrong side of the ray + return null; + + if (lambda > 1.0) // We're behind v2 + return null; + + if (lambda == 1.0 && !bEndsIncluded) + return null; // The end of the simplices are not included + + if (lambda < 0.0f) // we're before v1; + return null; + + return this.v1 + lambda * simplexDirection; + + } + + + } +}