public static double Cotangent(TriVertex thePoint, TriVertex basePt1, TriVertex basePt2) { double Eps = 0.000001; double crossProduct = XProduct(thePoint, basePt1, basePt2); return(Math.Abs(crossProduct) < Eps ? noCotangent : DotProduct(thePoint, basePt1, basePt2) / crossProduct); }
/// <summary> /// { Returns the triangle neighbouring aTriangle which is nearer to /// aPoint than aTriangle.If aPoint is in aTriangle then aTriangle is /// returned, and found set to true. If aPoint is outside the model, /// returns Nil - requires model to be convex. } /// </summary> /// <param name="aPoint"></param> /// <param name="aTriangle"></param> /// <param name="lastTri"></param> /// <param name="found"></param> /// <returns></returns> protected Triangle GetBestTri(TriVertex aPoint, Triangle aTriangle, Triangle lastTri, out bool found) { Triangle Result; found = false; TriVertex firstPoint = aTriangle.Vertices[0]; TriVertex secondPoint = aTriangle.Vertices[1]; if (aTriangle.Neighbours[0] != lastTri && TinningUtils.DefinitelyLeftOfBaseLine(aPoint, firstPoint, secondPoint)) { Result = aTriangle.Neighbours[0]; } else { TriVertex thirdPoint = aTriangle.Vertices[2]; if (aTriangle.Neighbours[1] != lastTri && TinningUtils.DefinitelyLeftOfBaseLine(aPoint, secondPoint, thirdPoint)) { Result = aTriangle.Neighbours[1]; } else if (aTriangle.Neighbours[2] != lastTri && TinningUtils.DefinitelyLeftOfBaseLine(aPoint, thirdPoint, firstPoint)) { Result = aTriangle.Neighbours[2]; } else // to the right of each line -must be inside aTriangle { Result = aTriangle; found = true; } } return(Result); }
public void Creation_FromCoordinates() { var vertex = new TriVertex(1, 2, 3); vertex.X = 1; vertex.Y = 2; vertex.Z = 3; }
public void IsEqual_WithTolerance() { var vertex1 = new TriVertex(1, 2, 3); var vertex2 = new TriVertex(1.1, 2.1, 3.1); vertex1.IsEqual(1, 2, 3, 0.0001).Should().BeTrue(); vertex2.IsEqual(1, 2, 3, 0.0001).Should().BeFalse(); vertex2.IsEqual(1, 2, 3, 0.2).Should().BeTrue(); }
public void IsEqual_Vertex() { var vertex1 = new TriVertex(1, 2, 3); var vertex2 = new TriVertex(1, 2, 3); var vertex3 = new TriVertex(2, 3, 4); vertex1.IsEqual(vertex2, 0.001).Should().BeTrue(); vertex1.IsEqual(vertex3, 0.001).Should().BeFalse(); }
public void Creation_FromXYZ() { var vertex = new TriVertex(1, 2, 3); var vertex2 = new TriVertex(vertex.XYZ); vertex2.X = 1; vertex2.Y = 2; vertex2.Z = 3; }
/// <summary> /// Add four coords to the model, which form the minimum bounding rectangle /// about the selected points.Return these. /// </summary> /// <param name="tl"></param> /// <param name="tr"></param> /// <param name="bl"></param> /// <param name="br"></param> protected void MakeMinimumBoundingRectangle(out TriVertex tl, out TriVertex tr, out TriVertex bl, out TriVertex br) { const int aBit = 10; // Arbitrary size expansion for encompassing rectangle tl = AddVertex(TIN.Header.MinimumEasting - aBit, TIN.Header.MaximumNorthing + aBit, 0); tr = AddVertex(TIN.Header.MaximumEasting + aBit, TIN.Header.MaximumNorthing + aBit, 0); bl = AddVertex(TIN.Header.MinimumEasting - aBit, TIN.Header.MinimumNorthing - aBit, 0); br = AddVertex(TIN.Header.MaximumEasting + aBit, TIN.Header.MinimumNorthing - aBit, 0); }
public void Test_Triangle_ToString() { var v1 = new TriVertex(0, 0, 0); var v2 = new TriVertex(0, 1, 0); var v3 = new TriVertex(1, 1, 0); var tri = new Triangle(v1, v2, v3); tri.ToString().Should().ContainAll(new[] { "Vertices:", "Neighbours:" }); }
public void Creation_SetFomXYZ() { var vertex = new TriVertex(0, 0, 0); var vertex2 = new TriVertex(vertex.XYZ); vertex.XYZ = vertex2.XYZ; vertex2.X = 1; vertex2.Y = 2; vertex2.Z = 3; }
public Triangle AddTriangle(TriVertex V1, TriVertex V2, TriVertex V3) { // Add the triangle and assign its tag member to be its position in the list (ie: it will be the last one) Triangle tri = TIN.Triangles.AddTriangle(V1, V2, V3); tri.Tag = TIN.Triangles.Count; TriangleAdded(tri); return(tri); }
public void Triangle_Area() { // Three clock wise coordinates var v1 = new TriVertex(0, 0, 0); var v2 = new TriVertex(0, 1, 0); var v3 = new TriVertex(1, 1, 0); var tri = new Triangle(v1, v2, v3); tri.Area().Should().Be(0.5); }
/// <summary> /// Add the two starting triangles. /// </summary> /// <param name="tl"></param> /// <param name="tr"></param> /// <param name="bl"></param> /// <param name="br"></param> protected void CreateInitialTriangles(TriVertex tl, TriVertex tr, TriVertex bl, TriVertex br) { AddTriangle(tl, tr, bl); AddTriangle(bl, tr, br); // Ensure their neighbours are correct TIN.Triangles[0].Neighbours[1] = TIN.Triangles[1]; TIN.Triangles[1].Neighbours[0] = TIN.Triangles[0]; TIN.Triangles.NumberTriangles(); }
public void Triangle_Centroid() { var v1 = new TriVertex(0, 0, 0); var v2 = new TriVertex(0, 1, 0); var v3 = new TriVertex(1, 1, 0); var tri = new Triangle(v1, v2, v3); tri.Centroid().Should().BeEquivalentTo(new XYZ((v1.X + v2.X + v3.X) / 3, (v1.Y + v2.Y + v3.Y) / 3, (v1.Z + v2.Z + v3.Z) / 3)); }
protected void UpdateNeighbour(Triangle theTri, TriVertex thePoint, Triangle newTri) { if (theTri != null) { for (int j = 0; j < 3; j++) { if (theTri.Vertices[j] == thePoint) { theTri.Neighbours[XYZ.PrevSide(j)] = newTri; } } } }
public void Triangle_GetSideIndex_AntiClockwise() { // Three clock wise coordinates var v1 = new TriVertex(0, 0, 0); var v2 = new TriVertex(0, 1, 0); var v3 = new TriVertex(1, 1, 0); var tri = new Triangle(v3, v2, v1); tri.GetSideIndex(v1, v2).Should().Be(1); tri.GetSideIndex(v2, v3).Should().Be(0); tri.GetSideIndex(v3, v1).Should().Be(2); }
public void Triangle_PointInTriangleInclusive() { var v1 = new TriVertex(0, 0, 0); var v2 = new TriVertex(0, 1, 0); var v3 = new TriVertex(1, 1, 0); var tri = new Triangle(v1, v2, v3); tri.PointInTriangleInclusive(0.5, 0.5).Should().Be(XYZ.PointInTriangleInclusive(v1.XYZ, v2.XYZ, v3.XYZ, 0.5, 0.5)); tri.PointInTriangleInclusive(0, 0).Should().Be(XYZ.PointInTriangleInclusive(v1.XYZ, v2.XYZ, v3.XYZ, 0, 0)); tri.PointInTriangleInclusive(0, 1.0).Should().Be(XYZ.PointInTriangleInclusive(v1.XYZ, v2.XYZ, v3.XYZ, 0, 1.0)); tri.PointInTriangleInclusive(1.0, 0).Should().Be(XYZ.PointInTriangleInclusive(v1.XYZ, v2.XYZ, v3.XYZ, 1.0, 0)); }
public void Triangle_Clockwise() { // Three clock wise coordinates var v1 = new TriVertex(0, 0, 0); var v2 = new TriVertex(0, 1, 0); var v3 = new TriVertex(1, 1, 0); var tri = new Triangle(v1, v2, v3); tri.IsClockwise().Should().BeTrue(); var tri2 = new Triangle(v3, v2, v1); tri2.IsClockwise().Should().BeFalse(); }
public void TinningEngineTetss_AddTriangle() { TinningEngine engine = new TinningEngine(); engine.TIN.Vertices.InitPointSearch(-10, -10, 10, 10, 10); TriVertex v0 = engine.AddVertex(0, 0, 0); TriVertex v1 = engine.AddVertex(1, 0, 0); TriVertex v2 = engine.AddVertex(0, 1, 0); Triangle t = engine.AddTriangle(v0, v1, v2); Assert.True(engine.TIN.Triangles.Count == 1); Assert.True(engine.TIN.Triangles[0] == t); }
public void TinningEngineTetss_AddVertex() { TinningEngine engine = new TinningEngine(); engine.TIN.Vertices.InitPointSearch(-10, -10, 10, 10, 10); TriVertex v = engine.AddVertex(1, 2, 3); Assert.True(v.X == 1); Assert.True(v.Y == 2); Assert.True(v.Z == 3); Assert.True(engine.TIN.Vertices.Count == 1); Assert.True(engine.TIN.Vertices[0] == v); }
/* Re-include if required, and add unit tests for them at that time. * /// <summary> * /// Ensure lastTri is not discarded (ie invalid). If so, return a valid triangle * /// </summary> * /// <param name="lastTri"></param> * protected void CheckLastTri(ref Triangle lastTri) * { * if (lastTri == null) * lastTri = TIN.Triangles[0]; * * if (lastTri.IsDiscardedFlag) * for (int i = 0; i < TIN.Triangles.Count; i++) * if (!TIN.Triangles[i].IsDiscardedFlag) * { * lastTri = TIN.Triangles[i]; * return; * } * * if (lastTri.IsDiscardedFlag) * lastTri = null; * } */ /// <summary> /// NOTE - if aPoint is possibly a point currently in the model, it is /// faster and safer to use getTriangle(). Do not assume that /// locateTriangle() will actually find the triangle that an existing /// point is a vertex of, due to floating point inaccuracies /// </summary> /// <param name="coord"></param> /// <param name="lastTri"></param> /// <param name="checkIt"></param> /// <returns></returns> protected Triangle LocateTriangle2(TriVertex coord, Triangle lastTri, bool checkIt) { int nSteps = 0; bool found = false; bool outsideModel = false; if (lastTri == null) { lastTri = TIN.Triangles[0]; } /* Re-include if required, and add unit tests for them at that time. * if (checkIt) * CheckLastTri(ref lastTri); */ if (lastTri == null) // No undiscarded triangles left { return(null); } int StartAt = 0; Triangle currentTri = lastTri; while (!outsideModel && !found) { if (++nSteps > MaxTriangleLocationSteps) { surfaceWalkOverflowCount++; nSteps = 0; // Try again from another start triangle StartAt = (StartAt + 7919) % TIN.Triangles.Count; // 7919 is an appropriate sized prime lastTri = TIN.Triangles[StartAt]; currentTri = lastTri; } Triangle nextTri = GetBestTri(coord, currentTri, lastTri, out found); lastTri = currentTri; currentTri = nextTri; outsideModel = currentTri == null; } return(found ? currentTri : null); }
protected Triangle NewTriangle(TriVertex coord1, TriVertex coord2, TriVertex coord3, Triangle side1, Triangle side2, Triangle side3) { Triangle result; if (succLastTriangle != null) { result = succLastTriangle; if (coord1.X == coord2.X && coord1.Y == coord2.Y || coord2.X == coord3.X && coord2.Y == coord3.Y || coord3.X == coord1.X && coord3.Y == coord1.Y) { // TIN.SaveToFile($@"C:\Temp\TINStateBeforeCoordNonUniquenessException({DateTime.Now.Ticks}).ttm", false); throw new TRexTINException($"Coordinates for new triangle are not unique {string.Concat(new object[] {coord1, coord2, coord3})}"); } result.Vertices[0] = coord1; result.Vertices[1] = coord2; result.Vertices[2] = coord3; TIN.Triangles.Add(result); TriangleAdded(result); } else { result = TIN.Triangles.AddTriangle(coord1, coord2, coord3); TriangleAdded(result); } if (result == side1 || result == side2 || result == side3) { throw new TRexTINException($"Triangle cannot be its own neighbour: Tri={result}, versus neighbours={string.Concat(new object[] {side1, side2, side3})}"); } result.Neighbours[0] = side1; result.Neighbours[1] = side2; result.Neighbours[2] = side3; return(result); }
/// <summary> /// IncorporateCoord adds a vertex into the TIN by locating the triangle /// the coordinate lies in then adding the vertex to the model /// </summary> /// <param name="theCoord"></param> /// <param name="currentTri"></param> /// <returns></returns> protected bool IncorporateCoord(TriVertex theCoord, ref Triangle currentTri) { bool result = false; currentTri = LocateTriangle2(theCoord, currentTri, false); if (currentTri != null) { AddCoordToModel(theCoord, currentTri); if (succLastTriangle != null) { throw new TRexTINException("Not all created triangles used."); } result = true; } return(result); }
private void InitialiseTriangleVertexOrdering() { v0 = ScanTri.Vertices[0]; v1 = ScanTri.Vertices[1]; v2 = ScanTri.Vertices[2]; // Sort the three vertices in ascending Y order. The three compares and swaps // are more efficient than calling qsort to do it. if (v0.Y > v1.Y) { MinMax.Swap(ref v0, ref v1); } if (v1.Y > v2.Y) { MinMax.Swap(ref v1, ref v2); } if (v0.Y > v1.Y) { MinMax.Swap(ref v0, ref v1); } }
/// <summary> /// Returns true if the circumcircle of theTri contains theCoordRec /// </summary> /// <param name="theTri"></param> /// <param name="theCoord"></param> /// <returns></returns> protected bool Influenced(Triangle theTri, TriVertex theCoord) { var result = false; double cotan = TinningUtils.Cotangent(theTri.Vertices[2], theTri.Vertices[0], theTri.Vertices[1]); if (cotan > -1E20) { double cNorth = ((theTri.Vertices[1].Y + theTri.Vertices[0].Y) / 2) - ((theTri.Vertices[1].X - theTri.Vertices[0].X) / 2) * cotan; double cEast = ((theTri.Vertices[1].X + theTri.Vertices[0].X) / 2) + ((theTri.Vertices[1].Y - theTri.Vertices[0].Y) / 2) * cotan; double radSq = Math.Pow(cNorth - theTri.Vertices[0].Y, 2) + Math.Pow(cEast - theTri.Vertices[0].X, 2); result = Math.Pow(theCoord.X - cEast, 2) + Math.Pow(theCoord.Y - cNorth, 2) < radSq; } return(result); }
protected void makeUpdatedTriangle(Triangle tri, TriVertex firstCoord, TriVertex secondCoord, TriVertex thirdCoord, Triangle firstSide, Triangle secondSide, Triangle thirdSide) { if (tri == firstSide || tri == secondSide || tri == thirdSide) { throw new TRexTINException($"Triangle cannot be its own neighbour: Tri={tri}, versus neighbours={string.Concat(new object[] {firstSide, secondSide, thirdSide})}"); } tri.Vertices[0] = firstCoord; tri.Vertices[1] = secondCoord; tri.Vertices[2] = thirdCoord; tri.Neighbours[0] = firstSide; tri.Neighbours[1] = secondSide; tri.Neighbours[2] = thirdSide; TriangleUpdated(tri); }
/// <summary> /// IncorporateCoordIntoTriangle adds a vertex into the given triangle /// already existing in the model /// </summary> /// <param name="theCoord"></param> /// <param name="tri"></param> public void IncorporateCoordIntoTriangle(TriVertex theCoord, Triangle tri) { // Noisy logging - reinclude as necessary //Log.LogDebug($"Incorporating vertex {theCoord} into triangle {tri}"); /* Handy debug code... * // If the coord being added is equivalent to any of the vertices of the trianlge being added into then there is nothing more to do here * if (theCoord.X == tri.Vertices[0].X && theCoord.Y == tri.Vertices[0].Y || * theCoord.X == tri.Vertices[1].X && theCoord.Y == tri.Vertices[1].Y || * theCoord.X == tri.Vertices[2].X && theCoord.Y == tri.Vertices[2].Y) * { * TIN.SaveToFile($@"C:\Temp\TINStateIncorporateCoordIntoTriangleExitWithMatchingVertex({DateTime.Now.Ticks}).ttm", false); * return; * } */ AddCoordToModel(theCoord, tri); if (succLastTriangle != null) { throw new TRexTINException("Not all created triangles used."); } }
public void AdjustLimits() { var vertex1 = new TriVertex(1, 2, 3); var vertex2 = new TriVertex(1.1, 2.1, 3.1); var vertex3 = new TriVertex(0.9, 1.9, 2.9); double minX = double.MaxValue, minY = double.MaxValue, minZ = double.MaxValue; double maxX = double.MinValue, maxY = double.MinValue, maxZ = double.MinValue; vertex1.AdjustLimits(ref minX, ref minY, ref minZ, ref maxX, ref maxY, ref maxZ); minX.Should().Be(1); minY.Should().Be(2); minZ.Should().Be(3); maxX.Should().Be(1); maxY.Should().Be(2); maxZ.Should().Be(3); vertex2.AdjustLimits(ref minX, ref minY, ref minZ, ref maxX, ref maxY, ref maxZ); minX.Should().Be(1); minY.Should().Be(2); minZ.Should().Be(3); maxX.Should().Be(1.1); maxY.Should().Be(2.1); maxZ.Should().Be(3.1); vertex3.AdjustLimits(ref minX, ref minY, ref minZ, ref maxX, ref maxY, ref maxZ); minX.Should().Be(0.9); minY.Should().Be(1.9); minZ.Should().Be(2.9); maxX.Should().Be(1.1); maxY.Should().Be(2.1); maxZ.Should().Be(3.1); }
public static void GradientFill(Graphics graphics, Rectangle target, Color startColor, Color endColor, GradientDirection direction) { if (!GradientFillSupported) { return; } var hdc = graphics.GetHdc(); try { var vertices = new TriVertex[] { new TriVertex(target.Left, target.Top, startColor), new TriVertex(target.Right, target.Bottom, endColor) }; var rectangles = new GradientRect[] { new GradientRect() { UpperLeft = 0, LowerRight = 1 } }; GradientFill(hdc, vertices, 2, rectangles, 1, direction == GradientDirection.Horizontal ? GRADIENT_FILL_RECT_H : GRADIENT_FILL_RECT_V); } finally { graphics.ReleaseHdc(hdc); } }
public GridToTINTriangle(TriVertex Vertex1, TriVertex Vertex2, TriVertex Vertex3) : base(Vertex1, Vertex2, Vertex3) { }
private void Create(IRenderLayer layer) { var zoom = Context.Zoom; var colors = layer.Colors.Data; int length = colors.Length; int size = layer.Points.Size; var data = layer.Points.Data; if (length != data.Length / size) { throw new Exception(); } this.points = new TriVertex[length]; TriVertex vertex; Color color; PointF p = new PointF((float)data[0], (float)data[1]); zoom.WorldToScreen(ref p); // Get correction distance float dx = (p.X - (int)p.X) * 2.0f; float dy = (p.Y - (int)p.Y) * 2.0f; // Create vertices. for (int i = 0; i < length; i++) { p.X = (float)data[size * i]; p.Y = (float)data[size * i + 1]; zoom.WorldToScreen(ref p); color = colors[i]; vertex = new TriVertex(); vertex.x = (int)(p.X + dx); vertex.y = (int)(p.Y + dy); vertex.Red = (ushort)(color.R << 8); vertex.Green = (ushort)(color.G << 8); vertex.Blue = (ushort)(color.B << 8); vertex.Alpha = (ushort)(color.A << 8); this.points[i] = vertex; } var triangles = layer.Indices.Data; length = triangles.Length / 3; this.elements = new GradientTriangle[length]; GradientTriangle e; // Create triangles. for (int i = 0; i < length; i++) { e = new GradientTriangle(); e.Vertex1 = (uint)triangles[3 * i]; e.Vertex2 = (uint)triangles[3 * i + 1]; e.Vertex3 = (uint)triangles[3 * i + 2]; this.elements[i] = e; } }
/// <summary> /// The GradientFill function fills rectangle and triangle structures /// </summary> /// <param name="hdc">Handle to the destination device contex</param> /// <param name="pVertex">Array of TRIVERTEX structures that each define a triangle vertex</param> /// <param name="nVertex">The number of vertices in pVertex</param> /// <param name="pMesh">an array of GRADIENT_RECT structures in rectangle mode</param> /// <param name="nMesh">The number of elements in pMesh</param> /// <param name="ulMode">Specifies gradient fill mode</param> /// <returns>If the function succeeds, the return value is true, false</returns> public static bool GradientFill([In] IntPtr hdc, TriVertex[] pVertex, uint nVertex, GradientRect[] pMesh, uint nMesh, GradientFillMode ulMode) { return Native.GradientFill(hdc, pVertex, nVertex, pMesh, nMesh, ulMode); }