public static float CalculateDimensionalValueAtIndex(SlicePoint p1, SlicePoint p2, float z, string precision = "0000") { var slope = (p1.Y - p2.Y) / (p1.X - p2.X); var intercept = p1.Y - (slope * p1.X); var rawVal = slope * z + intercept; // using floats we end up with some infinitesimal rounding errors, // so we need to set the precision to something reasonable. Default is 1/100th of a micron // I'm sure there's a better way than converting it to a string and then back to a float, // but that's what I've got right now, so that's what I'm doing. var strVal = rawVal.ToString($"0.{precision}"); return(float.Parse(strVal, CultureInfo.InvariantCulture.NumberFormat)); }
public void CalculateZIntercept_GetsZValuesFromAnyTwoFacets() { // easy math, 45deg, all positive, from origin var v1 = new Vertex { X = 0, Y = 0, Z = 0 }; var v2 = new Vertex { X = 10, Y = 10, Z = 10 }; var p1 = new SlicePoint { X = 5, Y = 5 }; var z1 = 5; // crosses x- and y- axes, negative z-slope var v3 = new Vertex { X = -5, Y = -10, Z = 15 }; var v4 = new Vertex { X = 7, Y = 10, Z = 7 }; var p2 = new SlicePoint { X = 4, Y = 5 }; var z2 = 9; // crosses z-axis var v5 = new Vertex { X = 11, Y = 6, Z = -3 }; var v6 = new Vertex { X = 17, Y = -4, Z = 7 }; var p3 = new SlicePoint { X = 14, Y = 1 }; var z3 = 2; // Again, this should work regardless of direction var rp1 = LinAlgUtils.CalculateZIntercept(v1, v2, z1); var rp2 = LinAlgUtils.CalculateZIntercept(v1, v2, z1); Assert.True(rp1 == rp2 && rp1 == p1); rp1 = LinAlgUtils.CalculateZIntercept(v3, v4, z2); rp2 = LinAlgUtils.CalculateZIntercept(v4, v3, z2); Assert.True(rp1 == rp2 && rp1 == p2); rp1 = LinAlgUtils.CalculateZIntercept(v5, v6, z3); rp2 = LinAlgUtils.CalculateZIntercept(v6, v5, z3); Assert.True(rp1 == rp2 && rp1 == p3); }
public void CalculateDimensionalValueAtIndex_CalculatesProperValuesAtMultipleAngles() { // easy math, 45dg all positive var p1 = new SlicePoint { X = 0, Y = 0 }; var p2 = new SlicePoint { X = 10, Y = 10 }; // crosses both axes var p3 = new SlicePoint { X = -3, Y = -1 }; var p4 = new SlicePoint { X = 10, Y = 7 }; // crosses Y-Axis, heading down var p5 = new SlicePoint { X = -5, Y = -2 }; var p6 = new SlicePoint { X = 16, Y = -14 }; // we shouldn't be using this for flat lines, but I'll make sure it works, regardless var p7 = new SlicePoint { X = 10, Y = 22 }; var p8 = new SlicePoint { X = 4, Y = 22 }; // Each time we should find the same value regardless of which point is placed first Assert.Equal(5, LinAlgUtils.CalculateDimensionalValueAtIndex(p1, p2, 5)); Assert.Equal(5, LinAlgUtils.CalculateDimensionalValueAtIndex(p2, p1, 5)); Assert.Equal(3, LinAlgUtils.CalculateDimensionalValueAtIndex(p3, p4, 3.5f)); Assert.Equal(3, LinAlgUtils.CalculateDimensionalValueAtIndex(p4, p3, 3.5f)); Assert.Equal(-10, LinAlgUtils.CalculateDimensionalValueAtIndex(p5, p6, 9)); Assert.Equal(-10, LinAlgUtils.CalculateDimensionalValueAtIndex(p6, p5, 9)); Assert.Equal(22, LinAlgUtils.CalculateDimensionalValueAtIndex(p7, p8, 16)); Assert.Equal(22, LinAlgUtils.CalculateDimensionalValueAtIndex(p8, p7, 16)); }
public void Slice(DynamicRenderMesh mesh, Camera camera) { slicePointsDictionary.Clear(); verticesDictionary.Clear(); slicePoints.Clear(); vertices.Clear(); texCoords.Clear(); indices.Clear(); triangles.Clear(); ResultMeshes.Clear(); FillVertices(mesh, camera); Vector2 A = new Vector2(99999.0f, 99999.0f), B = new Vector2(-99999.0f, -99999.0f); var tempLine = new Line2d(); var workedIndices = new List <int>(); var tempIndices = new List <int>(); foreach (var line in Lines) { for (var i = 0; i < 2; i++) { if (line.A[i] < A[i]) { A[i] = line.A[i]; } if (line.B[i] > B[i]) { B[i] = line.B[i]; } } } for (var i = 0; i < indices.Count / 3; i++) { var index = i * 3; var point0 = vertices[indices[index]]; var point1 = vertices[indices[index + 1]]; var point2 = vertices[indices[index + 2]]; if (!CheckAABB(ref point0, ref point1, ref point2, ref A, ref B)) { for (var j = 0; j < 3; j++) { tempIndices.Add(indices[index + j]); } continue; } for (var j = 0; j < 3; j++) { workedIndices.Add(indices[index + j]); } } if (workedIndices.Count == 0) { return; } var triangle = new Vector3[3]; var triangleT = new Vector2[3]; var tempCollisions = new List <Vector3>(); var tempTexCoords = new List <Vector2>(); var tempCollisionsEdgeIndices = new List <int>(); var newTriangles = new List <int>(); var info0 = CollisionInfo.Zero; var info1 = CollisionInfo.Zero; for (var i = 0; i < sliceLines.Count; i++) { var line = Lines[i]; var sliceLine = sliceLines[i]; var trianglesCount = workedIndices.Count / 3; for (var j = 0; j < trianglesCount; j++) { var index = j * 3; for (var l = 0; l < 3; l++) { triangle[l] = vertices[workedIndices[index + l]]; triangleT[l] = texCoords[workedIndices[index + l]]; } info0 = CollisionInfo.Zero; info1 = CollisionInfo.Zero; tempCollisions.Clear(); tempTexCoords.Clear(); tempCollisionsEdgeIndices.Clear(); newTriangles.Clear(); //looking for a point / intersection point of the triangle and line for (int k = 0, l = 2; k < 3; l = k, k++) { if (info1.Type != CollisionType.CT_NONE) { break; } var tPoint0 = triangle[l]; var tPoint1 = triangle[k]; var tTexCoord0 = triangleT[l]; var tTexCoord1 = triangleT[k]; tempLine.Point0.X = tPoint0.X; tempLine.Point0.Y = tPoint0.Y; tempLine.Point1.X = tPoint1.X; tempLine.Point1.Y = tPoint1.Y; float ua, ub; if (!GetUaUb(tempLine, line, out ua, out ub)) { //lines coincide? //Verify whether some point belongs line segment tempLine //if find - get result and break. } else { if (ub < 0.0f || ub > 1.0f) { continue; } var collisionPoint = tPoint0 + (tPoint1 - tPoint0) * ub; var collisionTexCoord = tTexCoord0 + (tTexCoord1 - tTexCoord0) * ub; if (tempCollisions.Count == 0 || !PointsCompare.Equals(tempCollisions[0], collisionPoint)) { tempCollisions.Add(collisionPoint); tempTexCoords.Add(collisionTexCoord); tempCollisionsEdgeIndices.Add(l); } if (ua < 0.0f || ua > 1.0f) { continue; } var pointType = CollisionType.CT_VERTEX; Vector3 point; Vector2 texCoord; var pointIndex = -1; var edgeIndex = -1; if (ub > 0.0f) { if (ub < 1.0f) { pointType = CollisionType.CT_EDGE; point = tempCollisions.Last(); texCoord = tempTexCoords.Last(); edgeIndex = l; } else { point = tPoint1; texCoord = tTexCoord1; pointIndex = workedIndices[index + k]; } } else { point = tPoint0; texCoord = tTexCoord0; pointIndex = workedIndices[index + l]; } if (info0.Type == CollisionType.CT_NONE) { info0.PointIndex = pointIndex; info0.Type = pointType; info0.Position = point; info0.TexCoord = texCoord; info0.EdgeIndex = edgeIndex; } else { if (pointIndex == -1 || info0.PointIndex != pointIndex) { info1.PointIndex = pointIndex; info1.Type = pointType; info1.Position = point; info1.TexCoord = texCoord; info1.EdgeIndex = edgeIndex; } } } } if (info1.Type == CollisionType.CT_NONE) { if (tempCollisions.Count == 0) { if (info0.Type == CollisionType.CT_NONE) { continue; } } else { if (tempCollisions.Count > 1) { //Perhaps the point inside the triangle var dir = line.Direction; for (var l = 0; l < 2; l++) { var p = l == 0 ? line.Point0 : line.Point1; if (PointInTriangle(ref triangle[0], ref triangle[1], ref triangle[2], ref p)) { var v0 = tempCollisions[1].Xy - tempCollisions[0].Xy; var v1 = p - tempCollisions[0].Xy; var k = (v1.Length / v0.Length); var z = tempCollisions[0].Z + (tempCollisions[1].Z - tempCollisions[0].Z) * k; var t = tempTexCoords[0] + (tempTexCoords[1] - tempTexCoords[0]) * k; if (info0.Type == CollisionType.CT_NONE) { info0.Type = CollisionType.CT_INSIDE; info0.Position = new Vector3(p.X, p.Y, z); info0.TexCoord = t; if (Vector2.Dot(dir, v0) > 0.0f) { info0.EdgeIndex = tempCollisionsEdgeIndices[0]; } else { info0.EdgeIndex = tempCollisionsEdgeIndices[1]; } tempCollisionsEdgeIndices.Remove(info0.EdgeIndex); } else { info1.Type = CollisionType.CT_INSIDE; info1.Position = new Vector3(p.X, p.Y, z); info1.TexCoord = t; info1.EdgeIndex = tempCollisionsEdgeIndices[0]; } } } } } } if (info0.Type == CollisionType.CT_NONE) { continue; } //Create new triangles, if we have two points of intersection, and they are not vertices int pi1 = 0, pi0 = 0; if (info1.Type != CollisionType.CT_NONE && (info0.Type != CollisionType.CT_VERTEX || info1.Type != CollisionType.CT_VERTEX)) { if (info1.Type == CollisionType.CT_VERTEX || (info1.Type == CollisionType.CT_EDGE && info0.Type == CollisionType.CT_INSIDE) || (info1.Type == CollisionType.CT_EDGE && info0.Type == CollisionType.CT_EDGE && (info0.EdgeIndex + 1) % 3 != info1.EdgeIndex) || (info0.Type == CollisionType.CT_INSIDE && info1.Type == CollisionType.CT_INSIDE && (info0.EdgeIndex + 1) % 3 != info1.EdgeIndex)) { var temp = info1; info1 = info0; info0 = temp; } if (!verticesDictionary.TryGetValue(info1.Position, out pi1)) { pi1 = vertices.Count; vertices.Add(info1.Position); texCoords.Add(info1.TexCoord); verticesDictionary.Add(info1.Position, pi1); } if (info0.Type == CollisionType.CT_VERTEX) //One point of intersection coincides with the vertex { pi0 = info0.PointIndex; int i0 = workedIndices[index], i1 = workedIndices[index + 1], i2 = workedIndices[index + 2]; if (i0 == info0.PointIndex) { i0 = i2; i2 = i1; } else { if (i2 == info0.PointIndex) { i2 = i0; i0 = i1; } } i1 = info0.PointIndex; newTriangles.AddRange(new[] { i0, i1, pi1, i1, i2, pi1 }); if (info1.Type == CollisionType.CT_INSIDE) //The second point inside the triangle { newTriangles.AddRange(new[] { i2, i0, pi1 }); } } else { if (!verticesDictionary.TryGetValue(info0.Position, out pi0)) { pi0 = vertices.Count; vertices.Add(info0.Position); texCoords.Add(info0.TexCoord); verticesDictionary.Add(info0.Position, pi0); } if (info1.Type != info0.Type) //One point crosses the brink, the second inside the triangle { var prev = info0.EdgeIndex == 0 ? 2 : info0.EdgeIndex - 1; prev = workedIndices[index + prev]; var next = info0.EdgeIndex == 2 ? 0 : info0.EdgeIndex + 1; next = workedIndices[index + next]; var curr = workedIndices[index + info0.EdgeIndex]; newTriangles.AddRange(new[] { prev, curr, pi1, curr, pi0, pi1, pi0, next, pi1, next, prev, pi1 }); } else { var c0 = workedIndices[index + info0.EdgeIndex]; var c1 = workedIndices[index + info1.EdgeIndex]; var c2 = workedIndices[index + ((info1.EdgeIndex + 1) % 3)]; if (info0.Type == CollisionType.CT_EDGE) { newTriangles.AddRange(new[] { c0, pi0, pi1, pi0, c1, pi1, pi1, c2, c0 }); } else { newTriangles.AddRange(new[] { c0, c1, pi0, c1, pi1, pi0, c1, c2, pi1, c2, c0, pi1, c0, pi0, pi1 }); } } } } int slicePointIndex; SlicePoint slicePoint; for (var l = 0; l < 2; l++) { if (l == 1 && info1.Type == CollisionType.CT_NONE) { break; } var position = l == 0 ? info0.Position.Xy : info1.Position.Xy; var pointIndex = l == 0 ? pi0 : pi1; if (!slicePointsDictionary.TryGetValue(position, out slicePointIndex)) { slicePoint = new SlicePoint { Coordinate = position }; slicePoint.Lines.Add(sliceLine); slicePoint.PreparePoint(); slicePointIndex = slicePoints.Count; slicePoints.Add(slicePoint); slicePointsDictionary.Add(position, slicePointIndex); } else { slicePoint = slicePoints[slicePointIndex]; } if (!slicePoint.Indices.Contains(pointIndex)) { slicePoint.Indices.Add(pointIndex); } } if (newTriangles.Count > 0) { for (var l = 0; l < 3; l++) { workedIndices[index + l] = newTriangles[l]; } newTriangles.RemoveRange(0, 3); workedIndices.InsertRange(index, newTriangles); var count = (newTriangles.Count / 3); j += count; trianglesCount += count; } } } for (var i = 0; i < workedIndices.Count / 3; i++) { var index = i * 3; var t = new Triangle(); for (var j = 0; j < 3; j++) { t.Indices[j] = workedIndices[index + j]; } triangles.Add(i, new TrianleConnections { Triangle = t }); } var ind = new List <int>(); var tempTriangle = new Triangle(); tempTriangle.Indices[1] = -1; foreach (var point in slicePoints) { point.PreparePoint(); foreach (var index in point.Indices) { ind.Clear(); ind.Add(index); tempTriangle.Indices[0] = index; //Duplicate the verticle several times for (var i = 1; i < point.Directions.Count; i++) { ind.Add(vertices.Count); vertices.Add(vertices[index]); texCoords.Add(texCoords[index]); } foreach (var t in triangles) { var tr = t.Value.Triangle; var id = Triangle.TriangleEquals(ref tempTriangle, ref tr); if (id > -1) { var center = (vertices[tr.Indices[0]].Xy + vertices[tr.Indices[1]].Xy + vertices[tr.Indices[2]].Xy) / 3.0f; var dir = (center - point.Coordinate).Normalized(); var angle = SlicePoint.GetAngle(ref dir); var ii = point.Directions.Count - 1; for (var j = 0; j < point.Directions.Count; j++) { if (angle < point.Directions[j]) { break; } ii = j; } tr.Indices[id] = ind[ii]; } } } } var invTransform = mesh.Transform * camera.ViewMatrix; invTransform.Invert(); for (var i = 0; i < vertices.Count; i++) { vertices[i] = Vector3.Transform(vertices[i], invTransform); } workedIndices.Clear(); foreach (var t in triangles) { foreach (var i in t.Value.Triangle.Indices) { workedIndices.Add(i); } } workedIndices.AddRange(tempIndices); triangleConnections.Clear(); triangles.Clear(); for (var i = 0; i < workedIndices.Count / 3; i++) { var index = i * 3; var t = new Triangle(); for (var j = 0; j < 3; j++) { t.Indices[j] = workedIndices[index + j]; List <int> l; if (!triangleConnections.TryGetValue(t.Indices[j], out l)) { l = new List <int>(); triangleConnections.Add(t.Indices[j], l); } l.Add(i); } triangles.Add(i, new TrianleConnections { Triangle = t }); } var mainMesh = true; while (triangles.Count > 0) { foundedTriangles.Clear(); FillTriangles(triangles.First().Key); if (mainMesh) { mesh.Create(vertices, texCoords, foundedTriangles, mesh.Material.DiffuseTextureMap, mesh.Material.TransparentTextureMap, mesh.TextureAngle, mesh.TextureSize); mainMesh = false; } else { var tmpMesh = new DynamicRenderMesh(MeshType.Hair); tmpMesh.Create(vertices, texCoords, foundedTriangles, mesh.Material.DiffuseTextureMap, mesh.Material.TransparentTextureMap, mesh.TextureAngle, mesh.TextureSize); tmpMesh.Transform = mesh.Transform; tmpMesh.Material.DiffuseColor = mesh.Material.DiffuseColor; tmpMesh.MeshAngle = mesh.MeshAngle; tmpMesh.MeshSize = mesh.MeshSize; var info = tmpMesh.GetMeshInfo(); var center = Vector3.Zero; var scale = PickingController.GetHairScale(ProgramCore.Project.ManType); foreach (var vert in info.Positions) { center.X += vert.X * scale; center.Y += vert.Y * scale; center.Z += vert.Z * scale; } center /= info.Positions.Count; tmpMesh.Position = center; ResultMeshes.Add(tmpMesh); } } }
// returns null if nothing was sliced // even when hit by the laser nothing might get sliced // this is because I limit the minimum size of a new // planetoid for performance reasons. // public Planetoid Slice(Ray2D laser, float laserPower, PlanetoidsManager manager) { if (_fading) { return(null); } try { Vector2 start = transform.InverseTransformPoint(laser.origin); Vector2 end = transform.InverseTransformPoint(laser.origin + laser.direction * Laser.LASER_DISTANCE); SlicePoint[] slicePoints = new SlicePoint[2]; Vector2[] vertices = _collider.points; int foundPoints = 0; for (int i = 0; i < vertices.Length && foundPoints <= 2; ++i) { //Calculate intersectionPoint //For formula see http://en.wikipedia.org/wiki/Line-line_intersection //I'm using x1, x2, ... since that's easier to write. float x1 = start.x, x2 = end.x, x3 = vertices[i].x, x4 = vertices[(i + 1) % vertices.Length].x; float y1 = start.y, y2 = end.y, y3 = vertices[i].y, y4 = vertices[(i + 1) % vertices.Length].y; Vector2 intersectionPoint = new Vector2( (((x1 * y2 - y1 * x2) * (x3 - x4)) - ((x1 - x2) * (x3 * y4 - y3 * x4))) / (((x1 - x2) * (y3 - y4)) - ((y1 - y2) * (x3 - x4))), (((x1 * y2 - y1 * x2) * (y3 - y4)) - ((y1 - y2) * (x3 * y4 - y3 * x4))) / (((x1 - x2) * (y3 - y4)) - ((y1 - y2) * (x3 - x4))) ); //See if the point is is actually on the side & laser. float startx = Mathf.Min(vertices[i].x, vertices[(i + 1) % vertices.Length].x); //side float endx = Mathf.Max(vertices[i].x, vertices[(i + 1) % vertices.Length].x); float starty = Mathf.Min(vertices[i].y, vertices[(i + 1) % vertices.Length].y); float endy = Mathf.Max(vertices[i].y, vertices[(i + 1) % vertices.Length].y); float start2x = Mathf.Min(start.x, end.x); //laser float end2x = Mathf.Max(start.x, end.x); float start2y = Mathf.Min(start.y, end.y); float end2y = Mathf.Max(start.y, end.y); if (intersectionPoint.x >= startx && intersectionPoint.x < endx && intersectionPoint.y >= starty && intersectionPoint.y < endy && intersectionPoint.x >= start2x && intersectionPoint.x < end2x && intersectionPoint.y >= start2y && intersectionPoint.y < end2y) { //Add to the slicePoints vector if you find anything // throws when too many points were found slicePoints[foundPoints] = new SlicePoint(intersectionPoint, i); ++foundPoints; } } if (foundPoints != 2) { throw new UnityException("Wrong number of points found while slicing: " + foundPoints); } //Calculate the number of sides each part of the rock will have int numberOfPoints1 = Mathf.Abs(slicePoints[0].side - slicePoints[1].side); int numberOfPoints2 = vertices.Length - numberOfPoints1; //numberOfPoints1 = min(numberOfPoints1, b2_maxPolygonVertices-2); //Make sure there aren't too many vertexes (Box2D 'limitation') //numberOfPoints2 = min(numberOfPoints2, b2_maxPolygonVertices-2); //I raised the max Polygon verts to 16 (default 8) so it will almost never happen, though when it does it's almost invisible //Create vectors to save the sides of each new rock Vector2[] sides1 = new Vector2[numberOfPoints1 + 2]; Vector2[] sides2 = new Vector2[numberOfPoints2 + 2]; //Filling in the first vector int counter = slicePoints[0].side + 1; for (var i = 0; i < numberOfPoints1; ++i) { if (counter >= vertices.Length) { throw new UnityException("Whoops, something wrong with the slicing. Should never happen, please report this."); //Should never go over 0 } sides1[i] = vertices[counter]; ++counter; } //Lastly add the intersection points to the sides1. sides1[numberOfPoints1 + 0] = slicePoints[1].point; //Since I add them to the back the second one found will always be the first one here. sides1[numberOfPoints1 + 1] = slicePoints[0].point; //Filling in the second one for (var i = 0; i < numberOfPoints2; ++i) { counter = counter % vertices.Length; sides2[i] = vertices[counter]; ++counter; } sides2[numberOfPoints2 + 0] = slicePoints[0].point; sides2[numberOfPoints2 + 1] = slicePoints[1].point; //Check if both new polygons are valid. Their size & winding will be checked, also they have to be convex. if (GetArea(sides1) < MINIMUM_AREA || GetArea(sides2) < MINIMUM_AREA) { throw new UnityException("At least one of the new planetoids is too small, not slicing for performance reasons."); } //Get some values needed to set later. Vector2 linVel = _rigidbody.velocity; float angleVel = _rigidbody.angularVelocity; Vector2 dir = laser.direction; Vector2 lr = new Vector2(-dir.y, dir.x); lr.Normalize(); lr *= laserPower; //Change this rock. Initialize(sides1, manager); //Make the other part. Planetoid newRock = manager.GetNewOrCashedPlanetoid(); newRock.Initialize(sides2, manager); newRock.transform.position = transform.position; newRock.transform.rotation = transform.rotation; newRock._rigidbody.velocity = linVel; newRock._rigidbody.angularVelocity = angleVel; newRock._density = _density; //Set Velocities. _rigidbody.AddForce(lr, ForceMode2D.Impulse); newRock._rigidbody.AddForce(-lr, ForceMode2D.Impulse); return(newRock); } catch (UnityException ex) { Debug.Log("Failed slicing: " + ex.Message); return(null); } catch { Debug.Log("Failed slicing for an unknown reason"); return(null); } }
public void Slice(DynamicRenderMesh mesh, Camera camera) { slicePointsDictionary.Clear(); verticesDictionary.Clear(); slicePoints.Clear(); vertices.Clear(); texCoords.Clear(); indices.Clear(); triangles.Clear(); ResultMeshes.Clear(); FillVertices(mesh, camera); Vector2 A = new Vector2(99999.0f, 99999.0f), B = new Vector2(-99999.0f, -99999.0f); var tempLine = new Line2d(); var workedIndices = new List<int>(); var tempIndices = new List<int>(); foreach (var line in Lines) { for (var i = 0; i < 2; i++) { if (line.A[i] < A[i]) A[i] = line.A[i]; if (line.B[i] > B[i]) B[i] = line.B[i]; } } for (var i = 0; i < indices.Count / 3; i++) { var index = i * 3; var point0 = vertices[indices[index]]; var point1 = vertices[indices[index + 1]]; var point2 = vertices[indices[index + 2]]; if (!CheckAABB(ref point0, ref point1, ref point2, ref A, ref B)) { for (var j = 0; j < 3; j++) tempIndices.Add(indices[index + j]); continue; } for (var j = 0; j < 3; j++) workedIndices.Add(indices[index + j]); } if (workedIndices.Count == 0) return; var triangle = new Vector3[3]; var triangleT = new Vector2[3]; var tempCollisions = new List<Vector3>(); var tempTexCoords = new List<Vector2>(); var tempCollisionsEdgeIndices = new List<int>(); var newTriangles = new List<int>(); var info0 = CollisionInfo.Zero; var info1 = CollisionInfo.Zero; for (var i = 0; i < sliceLines.Count; i++) { var line = Lines[i]; var sliceLine = sliceLines[i]; var trianglesCount = workedIndices.Count / 3; for (var j = 0; j < trianglesCount; j++) { var index = j * 3; for (var l = 0; l < 3; l++) { triangle[l] = vertices[workedIndices[index + l]]; triangleT[l] = texCoords[workedIndices[index + l]]; } info0 = CollisionInfo.Zero; info1 = CollisionInfo.Zero; tempCollisions.Clear(); tempTexCoords.Clear(); tempCollisionsEdgeIndices.Clear(); newTriangles.Clear(); //looking for a point / intersection point of the triangle and line for (int k = 0, l = 2; k < 3; l = k, k++) { if (info1.Type != CollisionType.CT_NONE) break; var tPoint0 = triangle[l]; var tPoint1 = triangle[k]; var tTexCoord0 = triangleT[l]; var tTexCoord1 = triangleT[k]; tempLine.Point0.X = tPoint0.X; tempLine.Point0.Y = tPoint0.Y; tempLine.Point1.X = tPoint1.X; tempLine.Point1.Y = tPoint1.Y; float ua, ub; if (!GetUaUb(tempLine, line, out ua, out ub)) { //lines coincide? //Verify whether some point belongs line segment tempLine //if find - get result and break. } else { if (ub < 0.0f || ub > 1.0f) continue; var collisionPoint = tPoint0 + (tPoint1 - tPoint0) * ub; var collisionTexCoord = tTexCoord0 + (tTexCoord1 - tTexCoord0) * ub; if (tempCollisions.Count == 0 || !PointsCompare.Equals(tempCollisions[0], collisionPoint)) { tempCollisions.Add(collisionPoint); tempTexCoords.Add(collisionTexCoord); tempCollisionsEdgeIndices.Add(l); } if (ua < 0.0f || ua > 1.0f) continue; var pointType = CollisionType.CT_VERTEX; Vector3 point; Vector2 texCoord; var pointIndex = -1; var edgeIndex = -1; if (ub > 0.0f) { if (ub < 1.0f) { pointType = CollisionType.CT_EDGE; point = tempCollisions.Last(); texCoord = tempTexCoords.Last(); edgeIndex = l; } else { point = tPoint1; texCoord = tTexCoord1; pointIndex = workedIndices[index + k]; } } else { point = tPoint0; texCoord = tTexCoord0; pointIndex = workedIndices[index + l]; } if (info0.Type == CollisionType.CT_NONE) { info0.PointIndex = pointIndex; info0.Type = pointType; info0.Position = point; info0.TexCoord = texCoord; info0.EdgeIndex = edgeIndex; } else { if (pointIndex == -1 || info0.PointIndex != pointIndex) { info1.PointIndex = pointIndex; info1.Type = pointType; info1.Position = point; info1.TexCoord = texCoord; info1.EdgeIndex = edgeIndex; } } } } if (info1.Type == CollisionType.CT_NONE) { if (tempCollisions.Count == 0) { if (info0.Type == CollisionType.CT_NONE) continue; } else { if (tempCollisions.Count > 1) { //Perhaps the point inside the triangle var dir = line.Direction; for (var l = 0; l < 2; l++) { var p = l == 0 ? line.Point0 : line.Point1; if (PointInTriangle(ref triangle[0], ref triangle[1], ref triangle[2], ref p)) { var v0 = tempCollisions[1].Xy - tempCollisions[0].Xy; var v1 = p - tempCollisions[0].Xy; var k = (v1.Length / v0.Length); var z = tempCollisions[0].Z + (tempCollisions[1].Z - tempCollisions[0].Z) * k; var t = tempTexCoords[0] + (tempTexCoords[1] - tempTexCoords[0]) * k; if (info0.Type == CollisionType.CT_NONE) { info0.Type = CollisionType.CT_INSIDE; info0.Position = new Vector3(p.X, p.Y, z); info0.TexCoord = t; if (Vector2.Dot(dir, v0) > 0.0f) info0.EdgeIndex = tempCollisionsEdgeIndices[0]; else info0.EdgeIndex = tempCollisionsEdgeIndices[1]; tempCollisionsEdgeIndices.Remove(info0.EdgeIndex); } else { info1.Type = CollisionType.CT_INSIDE; info1.Position = new Vector3(p.X, p.Y, z); info1.TexCoord = t; info1.EdgeIndex = tempCollisionsEdgeIndices[0]; } } } } } } if (info0.Type == CollisionType.CT_NONE) continue; //Create new triangles, if we have two points of intersection, and they are not vertices int pi1 = 0, pi0 = 0; if (info1.Type != CollisionType.CT_NONE && (info0.Type != CollisionType.CT_VERTEX || info1.Type != CollisionType.CT_VERTEX )) { if (info1.Type == CollisionType.CT_VERTEX || (info1.Type == CollisionType.CT_EDGE && info0.Type == CollisionType.CT_INSIDE) || (info1.Type == CollisionType.CT_EDGE && info0.Type == CollisionType.CT_EDGE && (info0.EdgeIndex + 1) % 3 != info1.EdgeIndex) || (info0.Type == CollisionType.CT_INSIDE && info1.Type == CollisionType.CT_INSIDE && (info0.EdgeIndex + 1) % 3 != info1.EdgeIndex)) { var temp = info1; info1 = info0; info0 = temp; } if (!verticesDictionary.TryGetValue(info1.Position, out pi1)) { pi1 = vertices.Count; vertices.Add(info1.Position); texCoords.Add(info1.TexCoord); verticesDictionary.Add(info1.Position, pi1); } if (info0.Type == CollisionType.CT_VERTEX) //One point of intersection coincides with the vertex { pi0 = info0.PointIndex; int i0 = workedIndices[index], i1 = workedIndices[index + 1], i2 = workedIndices[index + 2]; if (i0 == info0.PointIndex) { i0 = i2; i2 = i1; } else { if (i2 == info0.PointIndex) { i2 = i0; i0 = i1; } } i1 = info0.PointIndex; newTriangles.AddRange(new[] { i0, i1, pi1, i1, i2, pi1 }); if (info1.Type == CollisionType.CT_INSIDE) //The second point inside the triangle newTriangles.AddRange(new[] { i2, i0, pi1 }); } else { if (!verticesDictionary.TryGetValue(info0.Position, out pi0)) { pi0 = vertices.Count; vertices.Add(info0.Position); texCoords.Add(info0.TexCoord); verticesDictionary.Add(info0.Position, pi0); } if (info1.Type != info0.Type) //One point crosses the brink, the second inside the triangle { var prev = info0.EdgeIndex == 0 ? 2 : info0.EdgeIndex - 1; prev = workedIndices[index + prev]; var next = info0.EdgeIndex == 2 ? 0 : info0.EdgeIndex + 1; next = workedIndices[index + next]; var curr = workedIndices[index + info0.EdgeIndex]; newTriangles.AddRange(new[] { prev, curr, pi1, curr, pi0, pi1, pi0, next, pi1, next, prev, pi1 }); } else { var c0 = workedIndices[index + info0.EdgeIndex]; var c1 = workedIndices[index + info1.EdgeIndex]; var c2 = workedIndices[index + ((info1.EdgeIndex + 1) % 3)]; if (info0.Type == CollisionType.CT_EDGE) { newTriangles.AddRange(new[] { c0, pi0, pi1, pi0, c1, pi1, pi1, c2, c0 }); } else { newTriangles.AddRange(new[] { c0, c1, pi0, c1, pi1, pi0, c1, c2, pi1, c2, c0, pi1, c0, pi0, pi1}); } } } } int slicePointIndex; SlicePoint slicePoint; for (var l = 0; l < 2; l++) { if (l == 1 && info1.Type == CollisionType.CT_NONE) break; var position = l == 0 ? info0.Position.Xy : info1.Position.Xy; var pointIndex = l == 0 ? pi0 : pi1; if (!slicePointsDictionary.TryGetValue(position, out slicePointIndex)) { slicePoint = new SlicePoint { Coordinate = position }; slicePoint.Lines.Add(sliceLine); slicePoint.PreparePoint(); slicePointIndex = slicePoints.Count; slicePoints.Add(slicePoint); slicePointsDictionary.Add(position, slicePointIndex); } else slicePoint = slicePoints[slicePointIndex]; if (!slicePoint.Indices.Contains(pointIndex)) slicePoint.Indices.Add(pointIndex); } if (newTriangles.Count > 0) { for (var l = 0; l < 3; l++) workedIndices[index + l] = newTriangles[l]; newTriangles.RemoveRange(0, 3); workedIndices.InsertRange(index, newTriangles); var count = (newTriangles.Count / 3); j += count; trianglesCount += count; } } } for (var i = 0; i < workedIndices.Count / 3; i++) { var index = i * 3; var t = new Triangle(); for (var j = 0; j < 3; j++) t.Indices[j] = workedIndices[index + j]; triangles.Add(i, new TrianleConnections { Triangle = t }); } var ind = new List<int>(); var tempTriangle = new Triangle(); tempTriangle.Indices[1] = -1; foreach (var point in slicePoints) { point.PreparePoint(); foreach (var index in point.Indices) { ind.Clear(); ind.Add(index); tempTriangle.Indices[0] = index; //Duplicate the verticle several times for (var i = 1; i < point.Directions.Count; i++) { ind.Add(vertices.Count); vertices.Add(vertices[index]); texCoords.Add(texCoords[index]); } foreach (var t in triangles) { var tr = t.Value.Triangle; var id = Triangle.TriangleEquals(ref tempTriangle, ref tr); if (id > -1) { var center = (vertices[tr.Indices[0]].Xy + vertices[tr.Indices[1]].Xy + vertices[tr.Indices[2]].Xy) / 3.0f; var dir = (center - point.Coordinate).Normalized(); var angle = SlicePoint.GetAngle(ref dir); var ii = point.Directions.Count - 1; for (var j = 0; j < point.Directions.Count; j++) { if (angle < point.Directions[j]) break; ii = j; } tr.Indices[id] = ind[ii]; } } } } var invTransform = mesh.Transform * camera.ViewMatrix; invTransform.Invert(); for (var i = 0; i < vertices.Count; i++) { vertices[i] = Vector3.Transform(vertices[i], invTransform); } workedIndices.Clear(); foreach (var t in triangles) { foreach (var i in t.Value.Triangle.Indices) workedIndices.Add(i); } workedIndices.AddRange(tempIndices); triangleConnections.Clear(); triangles.Clear(); for (var i = 0; i < workedIndices.Count / 3; i++) { var index = i * 3; var t = new Triangle(); for (var j = 0; j < 3; j++) { t.Indices[j] = workedIndices[index + j]; List<int> l; if (!triangleConnections.TryGetValue(t.Indices[j], out l)) { l = new List<int>(); triangleConnections.Add(t.Indices[j], l); } l.Add(i); } triangles.Add(i, new TrianleConnections { Triangle = t }); } var mainMesh = true; while (triangles.Count > 0) { foundedTriangles.Clear(); FillTriangles(triangles.First().Key); if (mainMesh) { mesh.Create(vertices, texCoords, foundedTriangles, mesh.Material.DiffuseTextureMap, mesh.Material.TransparentTextureMap, mesh.TextureAngle, mesh.TextureSize); mainMesh = false; } else { var tmpMesh = new DynamicRenderMesh(MeshType.Hair); tmpMesh.Create(vertices, texCoords, foundedTriangles, mesh.Material.DiffuseTextureMap, mesh.Material.TransparentTextureMap, mesh.TextureAngle, mesh.TextureSize); tmpMesh.Transform = mesh.Transform; tmpMesh.Material.DiffuseColor = mesh.Material.DiffuseColor; tmpMesh.MeshAngle = mesh.MeshAngle; tmpMesh.MeshSize = mesh.MeshSize; var info = tmpMesh.GetMeshInfo(1.0f); var center = Vector3.Zero; var scale = PickingController.GetHairScale(ProgramCore.Project.ManType); foreach (var vert in info.Positions) { center.X += vert.X * scale; center.Y += vert.Y * scale; center.Z += vert.Z * scale; } center /= info.Positions.Count; tmpMesh.Position = center; ResultMeshes.Add(tmpMesh); } } }