//Returns the triangle in which a given point (ray) (x,y) is located. It returns the real coordinates of points that form the triangle in which the ray (x,y) goes trough the surface //Using Surface's technique for information public Vector3[] GetPositionTriangle(float x, float y, ShiftModes shiftApplied) { ShiftModes shiftm = shiftApplied; //detect shifting from technique if (shiftApplied == ShiftModes.AutoDetect) { shiftm = this.SurfaceTechnique.DetectShiftMode(); if (shiftm == ShiftModes.Both) { throw new ExceptionSurface("A horizontal and a vertical shift were both found in this surface's technique. Function GetPositionHeight cannot compute surfaces with a technique that uses shifts both horisontal and vertical! Please use only one kind of shift."); } } //get the tile where the position is located and check if the tile obtained is within surface limits. if not, throw exception Point tile = this.GetPositionTile(x, y, shiftApplied); if (!Misc.WithinBounds(tile, this.Size, -2, -2)) { throw new ExceptionSurface("The tile that contains the point (" + x + "," + y + ") is not within surface limits!"); //okay, uses offsets of -2 because: for once the tile number is one less than the points in a surface, which is returned in this.size. and another thing is that the function verifies in interval [0,size] but it must not include size in our case, because from 0 to size-1 is the boundary that includes all good points } HatchingMode tileHatch = this.GetTileHatching(tile.X, tile.Y); //determine the triangle from this tile that contains this point //same algorithm for any shift mode works Vector3 p1, p2; //points that determin the hatching line on this tile Vector3 A, B, C; //points of the triangle that contains this point if (tileHatch == HatchingMode.NWSE) { p1 = this.GetPointRealCoordinatesXYHeight(tile.X, tile.Y + 1, true); p2 = this.GetPointRealCoordinatesXYHeight(tile.X + 1, tile.Y, true); PointF pInter = Line2D.Intersection(Line2D.FromTwoPoints(p1.X, p1.Y, p2.X, p2.Y), new Line2D(x, y, 0, 1)); //determine the intersection point between a vertical line that goes through the point and the one that determines the hatching. The result can help determine which triangle exacly this point belongs to bool leftTriangle = true; // consider it is the left triangle first, for faster computing //lines were parallel and the point is on the right triangle if (float.IsInfinity(pInter.Y)) { if (x > p1.X) { leftTriangle = false; } } //lines not parallel, but the point is on the right triangle if (y > pInter.Y) { leftTriangle = false; } //set the triangle (obs: one point was not calculated) if (leftTriangle) { A = p1; B = p2; C = this.GetPointRealCoordinatesXYHeight(tile.X, tile.Y, true); } else //right triangle { A = p1; B = this.GetPointRealCoordinatesXYHeight(tile.X + 1, tile.Y + 1, true); C = p2; } } else //NESW { p1 = this.GetPointRealCoordinatesXYHeight(tile.X, tile.Y, true); p2 = this.GetPointRealCoordinatesXYHeight(tile.X + 1, tile.Y + 1, true); PointF pInter = Line2D.Intersection(Line2D.FromTwoPoints(p1.X, p1.Y, p2.X, p2.Y), new Line2D(x, y, 0, 1)); //determine the intersection point between a vertical line that goes through the point and the one that determines the hatching. The result can help determine which triangle exacly this point belongs to bool leftTriangle = true; // consider it is the left triangle first, for faster computing //lines were parallel and the point is on the right triangle if (float.IsInfinity(pInter.Y)) { if (x > p1.X) { leftTriangle = false; } } //lines not parallel, but the point is on the right triangle if (y < pInter.Y) { leftTriangle = false; } //set the triangle (obs: one point was not calculated) if (leftTriangle) { A = p1; B = this.GetPointRealCoordinatesXYHeight(tile.X, tile.Y + 1, true); C = p2; } else //right triangle { A = p1; B = p2; C = this.GetPointRealCoordinatesXYHeight(tile.X + 1, tile.Y, true); } } //returns the triangle in the form of an 3 elements array of Vector3 object. (The triangle is given clockwise, relative to the surface) Vector3[] triangle = new Vector3[3]; triangle[0] = A; triangle[1] = B; triangle[2] = C; return(triangle); }
//Returns the tile point that contains a certain position (x,y) on the surface //Using Surface's technique for information public Point GetPositionTile(float x, float y, ShiftModes shiftApplied) { Point tile = new Point(0, 0); //holds the result ShiftModes shiftm = shiftApplied; //detect shifting from technique if (shiftApplied == ShiftModes.AutoDetect) { shiftm = this.SurfaceTechnique.DetectShiftMode(); if (shiftm == ShiftModes.Both) { throw new ExceptionSurface("A horizontal and a vertical shift were both found in this surface's technique. Function GetPositionHeight cannot compute surfaces with a technique that uses shifts both horisontal and vertical! Please use only one kind of shift."); } } //different algortitms for different shift modes, although somehow analogues if (shiftm == ShiftModes.None) { //NO SHIFT mode (fast computing) tile.X = (int)Math.Floor(x / this.SurfaceTechnique.TileSize.Width); //the column this point is in tile.Y = (int)Math.Floor(y / this.SurfaceTechnique.TileSize.Height); //the row this point is in } else if (shiftm == ShiftModes.Horizontal) { //HORIZONTAL SHIFT mode tile.Y = (int)Math.Floor(y / this.SurfaceTechnique.TileSize.Height); //the row this point is in //lower/upper points line (projection on lower/upper points line of this tile line): int tileXLower, tileXUpper; //column of the tile in which the lower/upper projection of the point is located tileXLower = this.GetTileForProjectedX(tile.Y, x); tileXUpper = this.GetTileForProjectedX(tile.Y + 1, x); if (tileXLower == tileXUpper) //it is clearly in this tile { tile.X = tileXLower; } else //could be in either of these two or between them { Vector2 pLower, pUpper; //keep the positions of each couple of points that separate each two tiles in which the point might be bool found = false; //changes to true when the tile is found for (int i = Math.Min(tileXLower, tileXUpper) + 1; i <= Math.Max(tileXLower, tileXUpper); i++) //verify (agains the point) each line in between two consecutive tiles from the lowest possible tile to the highest one to see where the point is { pLower = this.GetPointRealCoordinatesXY(i, tile.Y, true); pUpper = this.GetPointRealCoordinatesXY(i, tile.Y + 1, true); PointF pInter = Line2D.Intersection(Line2D.FromTwoPoints(pUpper.X, pUpper.Y, pLower.X, pLower.Y), new Line2D(x, y, 0, 1)); //gets the intersection between the determination line (the line between these two tiles) and the projection line of the point on OX //the two cases when the point is to the left of the determination line (the line that separates the two tiles) which means the point belongs to the left tile -> i-1; if (pUpper.X > pLower.X) { if (y > pInter.Y) { tile.X = i - 1; found = true; break; } } if (pUpper.X < pLower.X) { if (y < pInter.Y) { tile.X = i - 1; found = true; break; } } } if (!found) { tile.X = Math.Max(tileXLower, tileXUpper); //is no tile is found in the left of each line that separates two lines (the determination lines) then the point is surely in the mostright tile from the series of tiles found } } } else if (shiftm == ShiftModes.Vertical) { //VERTICAL SHIFT mode // !!! NEEDS DONE FOR VERTICAL SHIFT AS WELL !!! } return(tile); }