using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Drawing;
using Debugger;
namespace Mars_Mission
{
public class classCave
{
public static int intStandardCaveCellDepth = classLandscape.intLandscapeCellWidth;
public classCaveCell[] cCells;
static double dblMaxAngleDeviationPerCell = Math.PI * .12;
static public Random rnd;
public classLandscapeCell LandscapeCell;
static public bool bolActive;
public classCaveCell cFurthestVisibleCellMovingUp;
public classCaveCell cFurthestVisibleCellMovingDown;
System.Windows.Forms.PictureBox picViewscreen;
//Bitmap bmpCells;
public classCave(ref Random RND, ref classLandscapeCell cLandscapeCell, int intAverageDepth)
{
rnd = RND;
LandscapeCell = cLandscapeCell;
picViewscreen = classLandscape.picViewscreen;
int intDepth = (int)(rnd.NextDouble() * 100000) % (int)((double)intAverageDepth * .75) + (int)((double)intAverageDepth * .5);
generateCave(intDepth);
}
/// <summary>
/// returns an array of points to draw a polygon. polygon appears on screen with ptPerspectiveGame of the game world located at ptPerspectiveOnScreen.
/// dblZoom of the classLandscape is used to resize the polygon.
/// </summary>
/// <param name="cCellPersepective">cave cell where ptPerspectiveGame can be found</param>
/// <param name="ptPerspectiveGame">point of view of the object at this location in the game world</param>
/// <param name="ptPerspectiveOnScreen">location on screen where the perspective game world location is positioned</param>
/// <returns></returns>
public Point[] getPolygonPoints(ref classCaveCell cCellPersepective, classMath.classDoubleCartesian ptPerspectiveGame, Point ptPerspectiveOnScreen)
{ return getPolygonPoints(ref cCellPersepective, ptPerspectiveGame, ptPerspectiveOnScreen, 100000); }
public Point[] getPolygonPoints(ref classCaveCell cCellPersepective, classMath.classDoubleCartesian ptPerspectiveGame, Point ptPerspectiveOnScreen, int intMaxCellVisible)
{
cFurthestVisibleCellMovingUp = cCellPersepective;
cFurthestVisibleCellMovingDown = cCellPersepective;
bool bolContinue = true;
classMath.classDoubleLine linViewLine = new classMath.classDoubleLine();
classMath.classDoubleCartesian ptIntersection = new classMath.classDoubleCartesian();
linViewLine.pt1 = ptPerspectiveGame;
do // look up
{
classMath.classDoubleLine[] linTests = new classMath.classDoubleLine[0];
if (cFurthestVisibleCellMovingUp.intMyIndex > 0)
{
cFurthestVisibleCellMovingUp = cFurthestVisibleCellMovingUp.cPreviousCell;
linViewLine.pt2 = cFurthestVisibleCellMovingUp.ptCenter;
Array.Resize<classMath.classDoubleLine>(ref linTests, linTests.Length + 2);
linTests[linTests.Length - 2] = new classMath.classDoubleLine(cFurthestVisibleCellMovingUp.cLeftWall.ptMine, cFurthestVisibleCellMovingUp.cNextCell.cLeftWall.ptMine);
linTests[linTests.Length - 1] = new classMath.classDoubleLine(cFurthestVisibleCellMovingUp.cRightWall.ptMine, cFurthestVisibleCellMovingUp.cNextCell.cRightWall.ptMine);
for (int intTestLines = 0; intTestLines < linTests.Length; intTestLines++)
{
if (classMath.LinesIntersect(linTests[intTestLines], linViewLine, ref ptIntersection))
{
bolContinue = false;
break;
}
}
}
else
bolContinue = false;
} while (bolContinue);
bolContinue = true;
cFurthestVisibleCellMovingDown = cCellPersepective;
do // look down
{
classMath.classDoubleLine[] linTests = new classMath.classDoubleLine[0];
if (cFurthestVisibleCellMovingDown.intMyIndex < cCells.Length - 2)
{
cFurthestVisibleCellMovingDown = cFurthestVisibleCellMovingDown.cNextCell;
linViewLine.pt2 = cFurthestVisibleCellMovingDown.ptCenter;
Array.Resize<classMath.classDoubleLine>(ref linTests, linTests.Length + 2);
linTests[linTests.Length - 2] = new classMath.classDoubleLine(cFurthestVisibleCellMovingDown.cLeftWall.ptMine, cFurthestVisibleCellMovingDown.cLeftWall.ptNext);
linTests[linTests.Length - 1] = new classMath.classDoubleLine(cFurthestVisibleCellMovingDown.cRightWall.ptMine, cFurthestVisibleCellMovingDown.cRightWall.ptNext);
for (int intTestLines = 0; intTestLines < linTests.Length; intTestLines++)
{
if (classMath.LinesIntersect(linTests[intTestLines], linViewLine, ref ptIntersection))
{
bolContinue = false;
break;
}
}
}
else
bolContinue = false;
} while (bolContinue);
/// move along right wall
/// from cCellPerspective to cFurthestDown
/// then cross from right to left of cFurthestdown
/// move along left wall
/// from cFurthest down to cFurthestUp
/// then cross from left to right of cFurthestUp
/// move along right wall
/// from cFurthestUp to cCellPerspective
///
int intNumCaves = cFurthestVisibleCellMovingDown.intMyIndex - cFurthestVisibleCellMovingUp.intMyIndex;
if (intNumCaves > intMaxCellVisible)
{
if (cFurthestVisibleCellMovingDown.intMyIndex - cCellPersepective.intMyIndex > intMaxCellVisible / 2
&& cCellPersepective.intMyIndex - cFurthestVisibleCellMovingUp.intMyIndex > intMaxCellVisible / 2)
{ // shorten cells up & down
cFurthestVisibleCellMovingUp = cCellPersepective;
for (int intCellCounter = 0; intCellCounter < intMaxCellVisible / 2; intCellCounter++)
cFurthestVisibleCellMovingUp = cFurthestVisibleCellMovingUp.cPreviousCell;
cFurthestVisibleCellMovingDown = cCellPersepective;
for (int intCellCounter = 0; intCellCounter < intMaxCellVisible / 2; intCellCounter++)
cFurthestVisibleCellMovingDown = cFurthestVisibleCellMovingDown.cNextCell;
}
else if (cFurthestVisibleCellMovingDown.intMyIndex - cCellPersepective.intMyIndex > intMaxCellVisible / 2)
{ // shorten cells down
int intMaxNumCellsDown = intMaxCellVisible - (cCellPersepective.intMyIndex - cFurthestVisibleCellMovingUp.intMyIndex);
cFurthestVisibleCellMovingDown = cCellPersepective;
for (int intCellCounter = 0; intCellCounter < intMaxNumCellsDown; intCellCounter++)
cFurthestVisibleCellMovingDown = cFurthestVisibleCellMovingDown.cNextCell;
}
else
{ // shorten cells up
int intMaxCellsUp = intMaxCellVisible - (cFurthestVisibleCellMovingDown.intMyIndex - cCellPersepective.intMyIndex);
cFurthestVisibleCellMovingUp = cCellPersepective;
for (int intCellCounter = 0; intCellCounter < intMaxCellsUp; intCellCounter++)
cFurthestVisibleCellMovingUp = cFurthestVisibleCellMovingUp.cPreviousCell;
}
intNumCaves = cFurthestVisibleCellMovingDown.intMyIndex - cFurthestVisibleCellMovingUp.intMyIndex;
}
classCaveCell cThisCell = cFurthestVisibleCellMovingUp;
classMath.classDoubleCartesian[] ptOrderedGamePoints = new classMath.classDoubleCartesian[2 * (intNumCaves + 1)+3];
int intPointCounter = 0;
while (cThisCell != cFurthestVisibleCellMovingDown.cNextCell)
{
ptOrderedGamePoints[intPointCounter++] = cThisCell.cRightWall.ptMine;
cThisCell = cThisCell.cNextCell;
}
ptOrderedGamePoints[intPointCounter++] = cThisCell.cRightWall.ptMine;
ptOrderedGamePoints[intPointCounter++] = cThisCell.cLeftWall.ptMine;
while (cThisCell != cFurthestVisibleCellMovingUp)
{
cThisCell = cThisCell.cPreviousCell;
ptOrderedGamePoints[intPointCounter++] = cThisCell.cLeftWall.ptMine;
}
ptOrderedGamePoints[intPointCounter++] = cThisCell.cRightWall.ptMine;
Point[] ptRetVal = new Point[ptOrderedGamePoints.Length];
classMath.classRadialCoor cRadEquivalent = new classMath.classRadialCoor();
for (intPointCounter = 0; intPointCounter < ptRetVal.Length; intPointCounter++)
{
cRadEquivalent.angle = classMath.arcTan(ptOrderedGamePoints[intPointCounter], ptPerspectiveGame);
cRadEquivalent.radius = classMath.distanceBetweenTwoPoints(ptPerspectiveGame, ptOrderedGamePoints[intPointCounter]);
cRadEquivalent.radius *= classLandscape.dblZoom;
ptRetVal[intPointCounter].X = (int)(ptPerspectiveOnScreen.X + cRadEquivalent.radius * Math.Cos(cRadEquivalent.angle));
ptRetVal[intPointCounter].Y = (int)(ptPerspectiveOnScreen.Y + cRadEquivalent.radius * Math.Sin(cRadEquivalent.angle));
}
return ptRetVal;
}
public static int intMoveCounter = 0;
public classCollisionResult moveCaveScape(ref classCollisionDetectionObject cCDO)
{
intMoveCounter = (intMoveCounter + 1) % 20;
if (cCDO.ptSurface.X == cCDO.ptEnd.X && cCDO.ptSurface.Y == cCDO.ptEnd.Y)
{
classCollisionResult cRetVal = new classCollisionResult();
cRetVal.eCollision = enuCollisionResult.no_Collision;
if (cCDO.eLoc == enuLocation.Cave)
{
cRetVal.cCavescaveCellWall = cCDO.cCaveCell.cLeftWall;
cRetVal.eLoc = enuLocation.Cave;
}
return cRetVal;
}
classCaveCell cCellStart = cCDO.cCaveCell == null ? cCells[0] : cCDO.cCaveCell;
classCaveCell cFindEndUp = cCellStart;
classCaveCell cFindEndDown = cCellStart;
classCaveCell cCellEnd = cCellStart;
classMath.classRadialCoor cRadMotion = new classMath.classRadialCoor(classMath.arcTan(cCDO.ptEnd, cCDO.ptSurface), classMath.distanceBetweenTwoPoints(cCDO.ptEnd, cCDO.ptSurface));
classCollisionResult cNearestCollision = new classCollisionResult();
cNearestCollision.cLandscapeCell = LandscapeCell;
cNearestCollision.eLoc = cCDO.ptEnd.Y > cCells[0].ptCenter.Y ? enuLocation.Cave : enuLocation.Surface;
cNearestCollision.cCavescaveCellWall = cCellEnd.cLeftWall;
bool bolContinue = true;
int intMaxCellMove = (int)Math.Ceiling(cRadMotion.radius / classLandscape.LandscapeCellWidth) + 5;
if (cCDO.ptEnd.Y < cCells[0].ptCenter.Y)
{
cCellEnd = cCells[0];
}
else
{
if (cCDO.cCaveCell == null)
cCDO.cCaveCell = cCells[0];
do
{
if ((cFindEndDown == null
|| Math.Abs ( cFindEndDown.intMyIndex - cCDO.cCaveCell.intMyIndex) >= intMaxCellMove
|| cFindEndDown.intMyIndex == cCells.Length -2)
&& (cFindEndUp == null
|| Math.Abs(cFindEndUp.intMyIndex - cCDO.cCaveCell.intMyIndex) >= intMaxCellMove))
{/// if we have gone to the limits of our search -> determine direction of motion & set cEnd/cStart accordingly
if (Math.Abs(cRadMotion.angle - cCDO.cCaveCell.angle) < Math.PI / 2)
{ // moving "down" towards next cells
cCellStart = cCDO.cCaveCell;
for (int intCellCounter = 0; intCellCounter < intMaxCellMove && cCellStart.cPreviousCell != null; intCellCounter++)
cCellStart = cCellStart.cPreviousCell;
cCellEnd = cCDO.cCaveCell;
for (int intCellCounter = 0; intCellCounter < intMaxCellMove && cCellEnd.cNextCell != null && cCellEnd.intMyIndex < cCells.Length -2; intCellCounter++)
cCellEnd = cCellEnd.cNextCell;
}
else
{ // moving "up" towards previous cells
cCellStart = cCDO.cCaveCell;
for (int intCellCounter = 0; intCellCounter < intMaxCellMove && cCellStart.cNextCell != null && cCellStart.intMyIndex < cCells.Length - 2; intCellCounter++)
cCellStart = cCellStart.cNextCell;
cCellEnd = cCDO.cCaveCell;
for (int intCellCounter = 0; intCellCounter < intMaxCellMove && cCellEnd.cPreviousCell != null; intCellCounter++)
cCellEnd = cCellEnd.cPreviousCell;
}
bolContinue = false;
}
else if (cFindEndDown != null
&& (cFindEndDown.pointIsInsideMe(cCDO.ptEnd)))
{
cCellEnd = cFindEndDown;
bolContinue = false;
}
else if (cFindEndUp != null
&& (cFindEndUp.pointIsInsideMe(cCDO.ptEnd)))
{
cCellEnd = cFindEndUp;
bolContinue = false;
}
else
{
if (cFindEndUp == null && (cFindEndDown == null || cFindEndDown.intMyIndex == cCells.Length-2))
{
// end-point is outside the cave
/// must define the limits of test using the start cell as reference
/// given the intended travelling distance f(start - end)
/// calculate the maximum number of cells by dividing distance/intAverageCellDepth
/// move away from start cell in either direction
/// calculate the direction of motion given the angle b/w start-end relative to the angle of start cell
/// given the direction of motion ("up" towards previous or "down" towards next)
/// set cellStart & cellEnd equal to the appropriate limits counted away from original start-cell
if (Math.Abs(cRadMotion.angle - cCDO.cCaveCell.angle) < Math.PI / 2)
{ // moving "down" towards next cells
cCellStart = cCDO.cCaveCell;
for (int intCellCounter = 0; intCellCounter < intMaxCellMove && cCellStart.cPreviousCell != null; intCellCounter++)
cCellStart = cCellStart.cPreviousCell;
cCellEnd = cCDO.cCaveCell;
for (int intCellCounter = 0; intCellCounter < intMaxCellMove && cCellEnd.cNextCell != null; intCellCounter++)
cCellEnd = cCellEnd.cNextCell;
}
else
{ // moving "up" towards previous cells
cCellStart = cCDO.cCaveCell;
for (int intCellCounter = 0; intCellCounter < intMaxCellMove && cCellStart.cNextCell != null && cCellStart.intMyIndex < cCells.Length -2; intCellCounter++)
cCellStart = cCellStart.cNextCell;
cCellEnd = cCDO.cCaveCell;
for (int intCellCounter = 0; intCellCounter < intMaxCellMove && cCellEnd.cPreviousCell != null; intCellCounter++)
cCellEnd = cCellEnd.cPreviousCell;
}
bolContinue = false;
}
else
{
if (cFindEndUp != null)
cFindEndUp = cFindEndUp.cPreviousCell;
if (cFindEndDown != null && cFindEndDown.intMyIndex < cCells.Length -2)
cFindEndDown = cFindEndDown.cNextCell;
}
}
} while (bolContinue);
}
bool bolMovingDownwards = (cCellEnd.intMyIndex > cCellStart.intMyIndex);
if (Math.Abs(cCellEnd.intMyIndex - cCellStart.intMyIndex) < intMaxCellMove)
{
if (bolMovingDownwards)
{
if (cCellEnd.intMyIndex < cCells.Length - 2)
cCellEnd = cCellEnd.cNextCell;
if (cCellStart.intMyIndex >0)
cCellStart = cCellStart.cPreviousCell;
}
else
{
if (cCellEnd.intMyIndex > 0)
cCellEnd = cCellEnd.cPreviousCell;
if (cCellStart.intMyIndex < cCells.Length - 2)
cCellStart = cCellStart.cNextCell;
}
}
while (cCellEnd.intMyIndex > cCells.Length - 2)
cCellEnd = cCellEnd.cPreviousCell;
/// rotate system around end point such that the new test-system has the start-end points on horizontal line with end point on the left
classMath.classDoubleRectangle cRecMotion = new classMath.classDoubleRectangle();
cRecMotion.X = cCDO.ptEnd.X;
cRecMotion.Y = cCDO.ptEnd.Y - cCDO.radius;
cRecMotion.Width = classMath.distanceBetweenTwoPoints(cCDO.ptEnd, cCDO.ptSurface);
cRecMotion.Height = 2 * cCDO.radius;
classMath.classDoubleCartesian dptRecMotion_TL = new classMath.classDoubleCartesian(cRecMotion.Left, cRecMotion.Top);
classMath.classDoubleCartesian dptRecMotion_TR = new classMath.classDoubleCartesian(cRecMotion.Right, cRecMotion.Top);
classMath.classDoubleCartesian dptRecMotion_BL = new classMath.classDoubleCartesian(cRecMotion.Left, cRecMotion.Bottom);
classMath.classDoubleCartesian dptRecMotion_BR = new classMath.classDoubleCartesian(cRecMotion.Right, cRecMotion.Bottom);
classMath.classDoubleCartesian dptRecMotion_Start = new classMath.classDoubleCartesian(cRecMotion.Right, cCDO.ptEnd.Y);
classMath.classDoubleCartesian dptIntersection = new classMath.classDoubleCartesian();
classCaveCell cThisCell = cCellStart;
classCaveCell cQuitCell = bolMovingDownwards ? cCellEnd.cNextCell : cCellEnd.cPreviousCell;
classMath.classDoubleCartesian dptThis_Left, dptThis_Right;
double dblInfinity = Math.Pow(2, 60);
cNearestCollision.dblDistance = cRadMotion.radius;
Bitmap bmpDebug = null;
classMath.classDoubleCartesian dptCommonPointOfRotation = cCDO.ptEnd.Copy();
Point ptDebugEndRef = new Point();
if (classLandscape.frmMain.DrawDebug)
{
/// debug images
/// draw rectangle of motion & start/end circles
bmpDebug = new Bitmap(test_Draw_Landscape___wo_bmp_II.formDebug.picDebug.Width, test_Draw_Landscape___wo_bmp_II.formDebug.picDebug.Height);
ptDebugEndRef = new Point((int)(bmpDebug.Width * .25), (int)(bmpDebug.Height * .5));
using (Graphics g = Graphics.FromImage(bmpDebug))
{
g.FillRectangle(classPensAndBrushes.brBlack, new Rectangle(0, 0, bmpDebug.Width, bmpDebug.Height));
Point ptRecTL = classLandscape.getPointScreen(dptRecMotion_TL, cCDO.ptEnd, ptDebugEndRef);
Point ptRecTR = classLandscape.getPointScreen(dptRecMotion_TR, cCDO.ptEnd, ptDebugEndRef);
Point ptRecBR = classLandscape.getPointScreen(dptRecMotion_BR, cCDO.ptEnd, ptDebugEndRef);
Point ptRecBL = classLandscape.getPointScreen(dptRecMotion_BL, cCDO.ptEnd, ptDebugEndRef);
g.DrawRectangle(classPensAndBrushes.pBlue1, new Rectangle(ptRecTL.X, ptRecTL.Y, ptRecTR.X - ptRecTL.X, ptRecBR.Y - ptRecTR.Y));
Point ptStartCenter = classLandscape.getPointScreen(dptRecMotion_Start, cCDO.ptEnd, ptDebugEndRef);
g.DrawEllipse(classPensAndBrushes.pGreen1, new Rectangle(ptStartCenter.X - (int)(cCDO.radius * classLandscape.dblZoom), ptStartCenter.Y - (int)(cCDO.radius * classLandscape.dblZoom), (int)(2 * cCDO.radius * classLandscape.dblZoom), (int)(2 * cCDO.radius * classLandscape.dblZoom)));
g.DrawEllipse(classPensAndBrushes.pPurple1, new Rectangle(ptDebugEndRef.X - (int)(cCDO.radius * classLandscape.dblZoom), ptDebugEndRef.Y - (int)(cCDO.radius * classLandscape.dblZoom), (int)(2 * cCDO.radius * classLandscape.dblZoom), (int)(2 * cCDO.radius * classLandscape.dblZoom)));
/// draw cavescape
classMath.classDoubleCartesian dptDebugLast_Left = getRotatedPoint_Left(ref cCDO, cThisCell, cRadMotion, !bolMovingDownwards);
classMath.classDoubleCartesian dptDebugLast_Right = getRotatedPoint_Right(ref cCDO, cThisCell, cRadMotion, !bolMovingDownwards);
Point ptDebugLast_Left = classLandscape.getPointScreen(dptDebugLast_Left, cCDO.ptEnd, ptDebugEndRef);
Point ptDebugLast_Right = classLandscape.getPointScreen(dptDebugLast_Right, cCDO.ptEnd, ptDebugEndRef);
classMath.classDoubleCartesian dptDebugThis_Right, dptDebugThis_Left;
Point ptDebugThis_Left, ptDebugThis_Right;
classCaveCell cDebugCell = cThisCell;
do
{
dptDebugThis_Left = getRotatedPoint_Left(ref cCDO, cDebugCell, cRadMotion, bolMovingDownwards);
dptDebugThis_Right = getRotatedPoint_Right(ref cCDO, cDebugCell, cRadMotion, bolMovingDownwards);
ptDebugThis_Left = classLandscape.getPointScreen(dptDebugThis_Left, cCDO.ptEnd, ptDebugEndRef);
ptDebugThis_Right = classLandscape.getPointScreen(dptDebugThis_Right, cCDO.ptEnd, ptDebugEndRef);
g.DrawLine(classPensAndBrushes.pWhite1, ptDebugLast_Left, ptDebugThis_Left);
g.DrawLine(classPensAndBrushes.pWhite1, ptDebugLast_Right, ptDebugThis_Right);
if (classLandscape.frmMain.drawPoints)
{
int intRadius = 2;
g.DrawEllipse(classPensAndBrushes.pWhite1, new Rectangle(ptDebugThis_Left.X - intRadius, ptDebugThis_Left.Y - intRadius, 2 * intRadius, 2 * intRadius));
g.DrawEllipse(classPensAndBrushes.pWhite1, new Rectangle(ptDebugLast_Left.X - intRadius, ptDebugLast_Left.Y - intRadius, 2 * intRadius, 2 * intRadius));
g.DrawEllipse(classPensAndBrushes.pWhite1, new Rectangle(ptDebugThis_Right.X - intRadius, ptDebugThis_Right.Y - intRadius, 2 * intRadius, 2 * intRadius));
g.DrawEllipse(classPensAndBrushes.pWhite1, new Rectangle(ptDebugLast_Right.X - intRadius, ptDebugLast_Right.Y - intRadius, 2 * intRadius, 2 * intRadius));
}
ptDebugLast_Left = ptDebugThis_Left;
ptDebugLast_Right = ptDebugThis_Right;
dptDebugLast_Left = dptDebugThis_Left;
dptDebugLast_Right = dptDebugThis_Right;
if (cDebugCell.cBottomWall != null)
{
classMath.classDoubleCartesian dptBottomLeft = classMath.RotateAboutCommonPoint(cCDO.ptEnd, cDebugCell.cBottomWall.ptBottomLeft, -cRadMotion.angle + Math.PI);
classMath.classDoubleCartesian dptBottomRight = classMath.RotateAboutCommonPoint(cCDO.ptEnd, cDebugCell.cBottomWall.ptBottomRight, -cRadMotion.angle + Math.PI);
Point ptBottomLeft = classLandscape.getPointScreen(dptBottomLeft, cCDO.ptEnd, ptDebugEndRef);
Point ptBottomRight = classLandscape.getPointScreen(dptBottomRight, cCDO.ptEnd, ptDebugEndRef);
g.DrawLine(classPensAndBrushes.pWhite1, ptBottomLeft, ptBottomRight);
}
cDebugCell = bolMovingDownwards ? cDebugCell.cNextCell : cDebugCell.cPreviousCell;
} while (cDebugCell != cQuitCell);
//bmpDebug.Save("c:\\temp\\marsmission\\cavespace.bmp");
}
}
classMath.classDoubleCartesian dptLast_Left = getRotatedPoint_Left(ref cCDO, cThisCell, cRadMotion, !bolMovingDownwards);
classMath.classDoubleCartesian dptLast_Right = getRotatedPoint_Right(ref cCDO, cThisCell, cRadMotion, !bolMovingDownwards);
//int intCollisionCounter = 0;
do
{
dptThis_Left = getRotatedPoint_Left(ref cCDO, cThisCell, cRadMotion, bolMovingDownwards);
dptThis_Right = getRotatedPoint_Right(ref cCDO, cThisCell, cRadMotion, bolMovingDownwards);
classMath.classDoubleCartesian dptTop = dptThis_Left;
classMath.classDoubleCartesian dptBottom = dptThis_Right;
for (enuLeftRight eLeftRight = enuLeftRight.Left; eLeftRight < enuLeftRight._numLeftRight; eLeftRight++)
{
if (eLeftRight == enuLeftRight.Bottom && cThisCell.cBottomWall == null)
{
/// there is no bottom wall and we're trying to do a bottom wall
/// therefore -> ignore
}
else
{
classCollisionResult cThisCollision = new classCollisionResult();
classCollisionResult cThisCircleCollision = new classCollisionResult();
switch (eLeftRight)
{
case enuLeftRight.Left:
cThisCircleCollision.cCavescaveCellWall
= cThisCollision.cCavescaveCellWall
= cThisCell.cLeftWall;
if (dptThis_Left.Y > dptLast_Left.Y)
{
dptBottom = dptThis_Left;
dptTop = dptLast_Left;
}
else
{
dptBottom = dptLast_Left;
dptTop = dptThis_Left;
}
break;
case enuLeftRight.Right:
cThisCircleCollision.cCavescaveCellWall
= cThisCollision.cCavescaveCellWall
= cThisCell.cRightWall;
if (dptThis_Right.Y > dptLast_Right.Y)
{
dptBottom = dptThis_Right;
dptTop = dptLast_Right;
}
else
{
dptBottom = dptLast_Right;
dptTop = dptThis_Right;
}
break;
case enuLeftRight.Bottom:
cThisCircleCollision.cCavescaveCellWall
= cThisCollision.cCavescaveCellWall
= cThisCell.cBottomWall;
classMath.classDoubleCartesian dptBottomLeft = classMath.RotateAboutCommonPoint(cCDO.ptEnd, cThisCell.cBottomWall.ptBottomLeft, -cRadMotion.angle + Math.PI);
classMath.classDoubleCartesian dptBottomRight = classMath.RotateAboutCommonPoint(cCDO.ptEnd, cThisCell.cBottomWall.ptBottomRight, -cRadMotion.angle + Math.PI);
if (dptBottomLeft.Y > dptBottomRight.Y)
{
dptBottom = dptBottomLeft;
dptTop = dptBottomRight;
}
else
{
dptBottom = dptBottomRight;
dptTop = dptBottomLeft;
}
break;
}
double dblAngleTangent = classMath.arcTan(dptTop, dptBottom);
double dblAngleNormal = dblAngleTangent - Math.PI / 2;
if (classMath.LinesIntersect(dptTop, dptBottom,
dptRecMotion_TL, dptRecMotion_TR,
ref dptIntersection)
|| classMath.LinesIntersect(dptTop, dptBottom,
dptRecMotion_TR, dptRecMotion_BR,
ref dptIntersection)
|| classMath.LinesIntersect(dptTop, dptBottom,
dptRecMotion_BR, dptRecMotion_BL,
ref dptIntersection)
|| classMath.LinesIntersect(dptTop, dptBottom,
dptRecMotion_BL, dptRecMotion_TL,
ref dptIntersection)
|| (classMath.PointIsInsideRectangle(dptBottom, cRecMotion) && classMath.PointIsInsideRectangle(dptTop, cRecMotion)))
{
cThisCollision.eLoc = enuLocation.Cave;
cThisCollision.dblDistance = dblInfinity;
// dptIntersectionTangent is the point at which a line going through ptLast & ptThis extending towards infinity
// meets the left side of a circle inside the rectangular path of motion
classMath.classDoubleCartesian dptIntersectionTangent = new classMath.classDoubleCartesian(); // angle of tangent is same as angle of line
classMath.classDoubleCartesian ptContact = null;// point on circle at furthest motion
if (dptTop.Y == dptBottom.Y)
{ // horizontal line -> collision with point furthest to right AND inside rectangular path of motion
if (classMath.PointIsInsideRectangle(dptTop, cRecMotion) && classMath.PointIsInsideRectangle(dptBottom, cRecMotion))
{
// both points are inside rectangle
ptContact = new classMath.classDoubleCartesian(dptBottom.X > dptTop.X ? dptBottom.X : dptTop.X, dptRecMotion_Start.Y);
}
else if (classMath.PointIsInsideRectangle(dptTop, cRecMotion))
{
ptContact = dptTop;
}
else if (classMath.PointIsInsideRectangle(dptBottom, cRecMotion))
{
ptContact = dptBottom;
}
else
{
ptContact = null;
}
}
else if (dptTop.X == dptBottom.X)
{ // vertical line ->
// if the line traverses dptRecMotion_Start.y
// -> collision with line at (dptBottom.x, dptRecMotion_Start.y)
// else
// -> collision with point closes to center inside rectangle
if (dptTop.Y < dptRecMotion_Start.Y
&& dptBottom.Y > dptRecMotion_Start.Y)
{ // traverses horizontal center line of rectangle
ptContact = new classMath.classDoubleCartesian(dptBottom.X, dptRecMotion_Start.Y);
}
else
{
if (Math.Abs(dptBottom.Y - dptRecMotion_Start.Y) < Math.Abs(dptTop.Y - dptRecMotion_Start.Y))
{
ptContact = dptBottom;
}
else
{
ptContact = dptTop;
}
}
}
else
{
double dblDeltaY = cCDO.radius * Math.Sin(dblAngleNormal);
dptIntersectionTangent.Y = dptRecMotion_Start.Y + dblDeltaY;
// find point on line at y = dptIntersectionTangent
classMath.classDoubleCartesian ptLeftInfinity = new classMath.classDoubleCartesian(-dblInfinity, dptIntersectionTangent.Y);
classMath.classDoubleCartesian ptRightInfinity = new classMath.classDoubleCartesian(dblInfinity, dptIntersectionTangent.Y);
classMath.LinesIntersect(ptLeftInfinity, ptRightInfinity, dptTop, dptBottom, ref dptIntersectionTangent);
if (dptIntersection.X >= dptRecMotion_Start.X)
{ // contact at start position
ptContact = null;
cThisCollision.dblDistance = 0;
}
else if (dptIntersectionTangent.Y >= (dptBottom.Y < dptTop.Y ? dptBottom.Y : dptTop.Y)
&& dptIntersectionTangent.Y <= (dptBottom.Y > dptTop.Y ? dptBottom.Y : dptTop.Y)
&& dptIntersectionTangent.X >= (dptBottom.X < dptTop.X ? dptBottom.X : dptTop.X)
&& dptIntersectionTangent.X <= (dptBottom.X > dptTop.X ? dptBottom.X : dptTop.X)
&& classMath.PointIsInsideRectangle(dptIntersectionTangent, cRecMotion))
{
double dblDeltaXWithdptIntersectionTangent = Math.Abs(cCDO.radius * Math.Cos(dblAngleNormal));
cThisCollision.dblDistance = dptRecMotion_Start.X - dptIntersectionTangent.X - dblDeltaXWithdptIntersectionTangent;
if (cThisCollision.dblDistance < 0)
cThisCollision.dblDistance = 0;
cThisCollision.dblAngleNormalToPointOfContact = cThisCollision.cCavescaveCellWall.dblNormal;
goto TestNearestCollision;
}
else
{
if (classMath.PointIsInsideRectangle(dptTop, cRecMotion) && classMath.PointIsInsideRectangle(dptBottom, cRecMotion))
{
// both points are inside rectangle
if (classMath.distanceBetweenTwoPoints(dptBottom, dptRecMotion_Start) < classMath.distanceBetweenTwoPoints(dptTop, dptRecMotion_Start))
{
ptContact = dptBottom;
}
else
{
ptContact = dptTop;
}
}
else if (classMath.PointIsInsideRectangle(dptTop, cRecMotion))
{
ptContact = dptTop;
}
else if (classMath.PointIsInsideRectangle(dptBottom, cRecMotion))
{
ptContact = dptBottom;
}
else
{
ptContact = null;
cThisCollision.dblDistance = 0;
}
}
}
// given point ptContact -> place object the furthest to the left inside rectangle AND to the right of ptContact
// calculate deltaY from dptRecMotion_Start.Y to ptContact.Y
if (ptContact != null)
{
double dblDeltaY = ptContact.Y - dptRecMotion_Start.Y;
double dblNormalizedDeltaY = dblDeltaY / cCDO.radius;
cThisCollision.dblAngleNormalToPointOfContact = Math.Asin(dblNormalizedDeltaY);
double dblDeltaX = Math.Abs(cCDO.radius * Math.Cos(cThisCollision.dblAngleNormalToPointOfContact));
cThisCollision.dblDistance = dptRecMotion_Start.X - ptContact.X - dblDeltaX;
}
TestNearestCollision:
int intMinDistance = 5;
if (Math.Abs(cThisCollision.dblDistance) < intMinDistance)
{
cThisCollision.dblDistance = 0;
}
if (cThisCollision.dblDistance < cNearestCollision.dblDistance && cThisCollision.dblDistance >= 0)
{
cThisCollision.eCollision = enuCollisionResult.crash;
cThisCollision.ptEnd = new classMath.classDoubleCartesian(cCDO.ptSurface.X + cThisCollision.dblDistance * Math.Cos(cRadMotion.angle), cCDO.ptSurface.Y + cThisCollision.dblDistance * Math.Sin(cRadMotion.angle));
cNearestCollision = cThisCollision;
}
}
classMath.classDoubleCartesian dptIntersectionWithCircle = new classMath.classDoubleCartesian();
if (classMath.LineIntersectsCircle(cCDO.ptEnd, cCDO.radius, dptTop, dptBottom, ref dptIntersectionWithCircle))
{
//given point ptContact -> place object the furthest to the left inside rectangle AND to the right of ptContact
//calculate deltaY from dptRecMotion_Start.Y to ptContact.Y
cThisCircleCollision.eLoc = enuLocation.Cave;
cThisCircleCollision.dblDistance = cRadMotion.radius;
double dblDistanceIntended = classMath.distanceBetweenTwoPoints(cCDO.ptEnd, cCDO.ptSurface);
double dblDistanceRejected = 0;
/// line is tangent to circle at new end point
/// normal line goes through center
double dblDistanceBetweenCircleCenterAndIntersection = classMath.distanceBetweenTwoPoints(dptIntersectionWithCircle, cCDO.ptEnd);
double dblAngleBetweenCircleCenterandIntersection = classMath.arcTan(cCDO.ptEnd, dptIntersectionWithCircle);
dblDistanceRejected = Math.Abs(dblDistanceBetweenCircleCenterAndIntersection * Math.Cos(dblAngleBetweenCircleCenterandIntersection));
if (dblDistanceRejected >= dblDistanceIntended)
dblDistanceRejected = dblDistanceIntended;
cThisCircleCollision.dblAngleNormalToPointOfContact = cThisCircleCollision.cCavescaveCellWall.dblNormal; //classMath.cleanAngle(dblAngleBetweenCircleCenterandIntersection + cRadMotion.angle);
cThisCircleCollision.dblDistance = dblDistanceIntended - dblDistanceRejected;
int intMin = 5;
if (Math.Abs(cThisCircleCollision.dblDistance) < intMin)
{
cThisCircleCollision.dblDistance = 0;
}
if (cThisCircleCollision.dblDistance < cNearestCollision.dblDistance)
{
cNearestCollision = cThisCircleCollision;
cThisCircleCollision.eCollision = enuCollisionResult.crash;
}
}
}
}
dptLast_Left = dptThis_Left;
dptLast_Right = dptThis_Right;
cThisCell = bolMovingDownwards ? cThisCell.cNextCell : cThisCell.cPreviousCell;
} while (cThisCell != cQuitCell);
if (cNearestCollision.dblDistance < cRadMotion.radius)
{
cCDO.ptEnd.X = cCDO.ptSurface.X + cNearestCollision.dblDistance * Math.Cos(cRadMotion.angle);
cCDO.ptEnd.Y = cCDO.ptSurface.Y + cNearestCollision.dblDistance * Math.Sin(cRadMotion.angle);
}
if (classLandscape.frmMain.DrawDebug)
{
classMath.classDoubleCartesian dptEnd = new classMath.classDoubleCartesian(dptRecMotion_Start.X - cNearestCollision.dblDistance, dptRecMotion_Start.Y);
Point ptEndCenter = classLandscape.getPointScreen(dptEnd, dptCommonPointOfRotation, ptDebugEndRef);
using (Graphics g = Graphics.FromImage(bmpDebug))
g.DrawEllipse(classPensAndBrushes.pRed1, new Rectangle(ptEndCenter.X - (int)(cCDO.radius * classLandscape.dblZoom), ptEndCenter.Y - (int)(cCDO.radius * classLandscape.dblZoom), (int)(2 * cCDO.radius * classLandscape.dblZoom), (int)(2 * cCDO.radius * classLandscape.dblZoom)));
test_Draw_Landscape___wo_bmp_II.formDebug.picDebug.Image = bmpDebug;
test_Draw_Landscape___wo_bmp_II.formDebug.picDebug.Refresh();
}
if (cCDO.ptEnd.Y > cCells[0].ptCenter.Y)
{
cCDO.cCaveCell = cNearestCollision.cCavescaveCellWall.cMyCaveCell;
cCDO.eLoc = enuLocation.Cave;
cNearestCollision.ptEnd = cCDO.ptEnd;
setCaveCell(ref cCDO);
}
else
{
cCDO.cCaveCell = null;
cCDO.eLoc = enuLocation.Surface;
cNearestCollision.ptEnd = cCDO.ptEnd;
}
if (cCDO.eLoc == enuLocation.Cave)
{
classCaveCell.classCaveCellWall.intCounter = 0;
cCDO.cCaveCell.cLeftWall.Push(ref cCDO.ptSurface, cCDO.radius);
classCaveCell.classCaveCellWall.intCounter = 0;
cCDO.cCaveCell.cRightWall.Push(ref cCDO.ptSurface, cCDO.radius);
if (cCDO.cCaveCell.cBottomWall != null)
{
cCDO.cCaveCell.cBottomWall.Push(ref cCDO.ptSurface, cCDO.radius);
}
setCaveCell(ref cCDO);
}
return cNearestCollision;
}
classMath.classDoubleCartesian getRotatedPoint_Left(ref classCollisionDetectionObject cCDO, classCaveCell cThisCell, classMath.classRadialCoor cRadMotion, bool bolMovingDownwards)
{
return bolMovingDownwards
? classMath.RotateAboutCommonPoint(cCDO.ptEnd, cThisCell.cLeftWall.ptNext, -cRadMotion.angle + Math.PI )
: classMath.RotateAboutCommonPoint(cCDO.ptEnd, cThisCell.cLeftWall.ptMine, -cRadMotion.angle + Math.PI);
}
classMath.classDoubleCartesian getRotatedPoint_Right(ref classCollisionDetectionObject cCDO, classCaveCell cThisCell, classMath.classRadialCoor cRadMotion, bool bolMovingDownwards)
{
return bolMovingDownwards
? classMath.RotateAboutCommonPoint(cCDO.ptEnd, cThisCell.cRightWall.ptNext, -cRadMotion.angle + Math.PI)
: classMath.RotateAboutCommonPoint(cCDO.ptEnd, cThisCell.cRightWall.ptMine, -cRadMotion.angle + Math.PI);
}
/// <summary>
/// tests if the ptSurface of this object is find in this object's current caveCell.
/// if the ptSurface is not inside the specified cell then the caveCell is reset to match ptSurface
/// </summary>
/// <param name="cCDO">reference to a collision detection object class</param>
public void setCaveCell(ref classCollisionDetectionObject cCDO)
{
int intMaxSearch = 15;
if (!cCDO.cCaveCell.pointIsInsideMe(cCDO.ptSurface))
{
classCaveCell cFindUp = cCDO.cCaveCell.cPreviousCell;
classCaveCell cFindDown = cCDO.cCaveCell.cNextCell;
for (int intFindCell = 0; intFindCell < intMaxSearch; intFindCell++)
{
if (cFindUp != null)
if (cFindUp.pointIsInsideMe(cCDO.ptSurface))
{
cCDO.cCaveCell = cFindUp;
return;
}
else
cFindUp = cFindUp.cPreviousCell;
if (cFindDown != null)
if (cFindDown.pointIsInsideMe(cCDO.ptSurface))
{
cCDO.cCaveCell = cFindDown;
return;
}
else
cFindDown = cFindDown.cNextCell;
}
}
}
enum enuLeftRight {Left =0, Right, Bottom, _numLeftRight};
/// <summary>
/// assumes point of view is set to the center of the screen and uses the same dblZoom as classLandscape
/// </summary>
/// <param name="cCDO"></param>
/// <returns></returns>
public Bitmap getViewScreen(ref classCollisionDetectionObject cCDO) { return getViewScreen(ref cCDO, false); }
public Bitmap getViewScreen(ref classCollisionDetectionObject cCDO, bool bolWithLandscape)
{
if (picViewscreen.Width < 10 || picViewscreen.Height < 10)
return null;
Bitmap bmpRetVal = bolWithLandscape
? LandscapeCell.cLandscape.getViewScreen(cCDO.ptSurface, true)
: new Bitmap(picViewscreen.Width, picViewscreen.Height);
using (Graphics g = Graphics.FromImage(bmpRetVal))
{
if (!bolWithLandscape)
g.FillRectangle(LandscapeCell.cLandscape.brMyDirt, new Rectangle(0, 0, bmpRetVal.Width, bmpRetVal.Height));
Point[] ptPolygon = getPolygonPoints(ref cCDO.cCaveCell, cCDO.ptSurface, classLandscape.ptCenterScreen);
g.FillPolygon(LandscapeCell.cLandscape.brMyCave, ptPolygon);
if (classLandscape.frmMain.drawPoints)
{
int intRadius = 2;
for (int intPointCounter = 0; intPointCounter < ptPolygon.Length; intPointCounter++)
{
g.DrawEllipse(classPensAndBrushes.pWhite1, new Rectangle(ptPolygon[intPointCounter].X -intRadius, ptPolygon[intPointCounter].Y - intRadius, intRadius*2, intRadius*2));
}
}
}
return bmpRetVal;
}
classCaveCell getNearestCenter(classMath.classDoubleCartesian pt)
{
return new classCaveCell();
}
Point convertGameWorldPointToBmpCellLocationPoints(classMath.classDoubleCartesian ptGameWorld)
{
double dblRatio = 100;
return new Point((int)(ptGameWorld.X / dblRatio), (int)(ptGameWorld.Y / dblRatio));
}
void generateCave(int intDepth)
{
classMath.classDoubleCartesian.bolClassLock = false;
cCells = new classCaveCell[intDepth];
// generate all cells
for (int intCellCounter = 0; intCellCounter < cCells.Length; intCellCounter++)
{
cCells[intCellCounter] = new classCaveCell();
cCells[intCellCounter].intMyIndex = intCellCounter;
cCells[intCellCounter].cLeftWall = new classCaveCell.classCaveCellWall();
cCells[intCellCounter].cLeftWall.cMyCaveCell = cCells[intCellCounter];
cCells[intCellCounter].cRightWall = new classCaveCell.classCaveCellWall();
cCells[intCellCounter].cRightWall.cMyCaveCell = cCells[intCellCounter];
cCells[intCellCounter].cCave = this;
}
// connect all cells
for (int intCellCounter = 0; intCellCounter < cCells.Length; intCellCounter++)
{
if (intCellCounter > 0)
cCells[intCellCounter].cPreviousCell = cCells[intCellCounter - 1];
if (intCellCounter < cCells.Length - 1)
cCells[intCellCounter].cNextCell = cCells[intCellCounter + 1];
}
Point ptTL = convertGameWorldPointToBmpCellLocationPoints(LandscapeCell.ptLeft);
Point ptBR = convertGameWorldPointToBmpCellLocationPoints(LandscapeCell.ptRight);
cCells[0].cCave = this;
cCells[0].cLeftWall.ptMine= LandscapeCell.ptLeft;
cCells[0].cRightWall.ptMine = LandscapeCell.ptRight;
cCells[0].ptCenter = classMath.findCenterOfLine(cCells[0].cLeftWall.ptMine, cCells[0].cRightWall.ptMine);
cCells[0].eBottomType = enuLandscapeCellType.empty;
cCells[0].eLeftType
= cCells[0].eRightType
= enuLandscapeCellType.caveMouth;
cCells[0].cCave = this;
cCells[0].dblDepth = 0;
cCells[0].dblWidth = classLandscape.intLandscapeCellWidth;
cCells[0].angle = Math.PI / 2;
cCells[0].intMyIndex = 0;
classMath.classDoubleCartesian ptIntersection = new classMath.classDoubleCartesian();
int intNumInRow = 0;
int intSizeChangeSign = 1;
int intMinDepthCellCounter = 20;
double dblMinDepth = cCells[0].ptCenter.Y + intMinDepthCellCounter * classLandscape.LandscapeCellWidth;
double dblMinWidth = 1.25 * classLandscape.LandscapeCellWidth;
for (int intCellCounter = 1; intCellCounter < cCells.Length; intCellCounter++)
{
classCaveCell cThisCell = cCells[intCellCounter];
intNumInRow--;
if (intCellCounter > cCells.Length - 10)
{
intSizeChangeSign = -1;
int intSizeChangeNeeded = (int)cThisCell.cPreviousCell.dblWidth - classLandscape.intLandscapeCellWidth;
int intNumCellsLeft = cCells.Length - intCellCounter;
int intMinChange = intSizeChangeNeeded / (intNumCellsLeft + 2);
cThisCell.dblWidth = cThisCell.cPreviousCell.dblWidth
- intMinChange
- (int)(rnd.NextDouble() * intMinChange);
if (cThisCell.intMyIndex < cCells.Length -1)
{
if (cThisCell.dblWidth < dblMinWidth)
cThisCell.dblWidth = dblMinWidth;
}
else
cThisCell.dblWidth = dblMinWidth / 2;
}
else
{
if (intNumInRow <= 0)
{
if (cThisCell.cPreviousCell.dblWidth == dblMinWidth)
intSizeChangeSign = 1;
else
{
intSizeChangeSign *= -1;
}
intNumInRow = (int)(rnd.NextDouble() * 1000) % 20 + 5;
}
cThisCell.dblWidth = (rnd.NextDouble() * .75) * intSizeChangeSign * classLandscape.LandscapeCellWidth + cThisCell.cPreviousCell.dblWidth; // (.5 prev-width) < new width < (1.5 prev-width)
if (cThisCell.dblWidth < dblMinWidth)
{
cThisCell.dblWidth = dblMinWidth;
}
}
do
{
cThisCell.dblDepth = intStandardCaveCellDepth;//(int)((double)intStandardCaveCellDepth * (rnd.NextDouble() * 2.0 - 1.0) + 2.0 * (double)intStandardCaveCellDepth);
if ((cThisCell.intMyIndex > intMinDepthCellCounter
&& cThisCell.cPreviousCell.cLeftWall.ptMine.Y < dblMinDepth
&& cThisCell.cPreviousCell.angle > 1.5 * Math.PI)
|| (cThisCell.intMyIndex < intMinDepthCellCounter
&& cThisCell.cPreviousCell.angle >1.5 * Math.PI))
{
cThisCell.angle = classMath.cleanAngle(cThisCell.cPreviousCell.angle + rnd.NextDouble() * classCave.dblMaxAngleDeviationPerCell);
if (cThisCell.dblWidth > dblMinWidth)
{
cThisCell.dblWidth *= .9;
if (cThisCell.dblWidth < dblMinWidth)
cThisCell.dblWidth = dblMinWidth;
}
}
else if ((cThisCell.intMyIndex > intMinDepthCellCounter
&& cThisCell.cPreviousCell.cRightWall.ptMine.Y < dblMinDepth
&& cThisCell.cPreviousCell.angle > Math.PI)
|| (cThisCell.intMyIndex < intMinDepthCellCounter
&& cThisCell.cPreviousCell.angle > Math.PI))
{
cThisCell.angle = classMath.cleanAngle(cThisCell.cPreviousCell.angle - rnd.NextDouble() * classCave.dblMaxAngleDeviationPerCell);
if (cThisCell.dblWidth > dblMinWidth)
{
cThisCell.dblWidth *= .9;
if (cThisCell.dblWidth < dblMinWidth)
cThisCell.dblWidth = dblMinWidth;
}
}
else
cThisCell.angle = classMath.cleanAngle(cThisCell.cPreviousCell.angle + rnd.NextDouble() * classCave.dblMaxAngleDeviationPerCell * 2.0 - classCave.dblMaxAngleDeviationPerCell);
cThisCell.ptCenter = new classMath.classDoubleCartesian(cThisCell.cPreviousCell.ptCenter.X + cThisCell.dblDepth * Math.Cos(cThisCell.cPreviousCell.angle),
cThisCell.cPreviousCell.ptCenter.Y + cThisCell.dblDepth * Math.Sin(cThisCell.cPreviousCell.angle));
cThisCell.cLeftWall.ptMine = new classMath.classDoubleCartesian(cThisCell.ptCenter.X + cThisCell.dblWidth / 2.0 * Math.Cos(cThisCell.angle + Math.PI / 2.0),
cThisCell.ptCenter.Y + cThisCell.dblWidth / 2.0 * Math.Sin(cThisCell.angle + Math.PI / 2.0));
cThisCell.cRightWall.ptMine = new classMath.classDoubleCartesian(cThisCell.ptCenter.X + cThisCell.dblWidth / 2.0 * Math.Cos(cThisCell.angle - Math.PI / 2.0),
cThisCell.ptCenter.Y + cThisCell.dblWidth / 2.0 * Math.Sin(cThisCell.angle - Math.PI / 2.0));
} while
(
classMath.LinesIntersect(cThisCell.cLeftWall.ptMine, cThisCell.cRightWall.ptMine, cThisCell.cPreviousCell.cLeftWall.ptMine, cThisCell.cPreviousCell.cRightWall.ptMine, ref ptIntersection)
);
/*
//stretch limits of bmpCellLoc
Point ptBmpCellLoc_Left = convertGameWorldPointToBmpCellLocationPoints(cThisCell.ptLeft);
if (ptBmpCellLoc_Left.X < ptTL.X)
ptTL.X = ptBmpCellLoc_Left.X;
if (ptBmpCellLoc_Left.X > ptBR.X)
ptBR.X = ptBmpCellLoc_Left.X;
if (ptBmpCellLoc_Left.Y < ptTL.Y)
ptTL.Y = ptBmpCellLoc_Left.Y;
if (ptBmpCellLoc_Left.Y > ptBR.Y)
ptBR.Y = ptBmpCellLoc_Left.Y;
Point ptBmpCellLoc_Right = convertGameWorldPointToBmpCellLocationPoints(cThisCell.ptRight);
if (ptBmpCellLoc_Right.X < ptTL.X)
ptTL.X = ptBmpCellLoc_Right.X;
if (ptBmpCellLoc_Right.X > ptBR.X)
ptBR.X = ptBmpCellLoc_Right.X;
if (ptBmpCellLoc_Right.Y < ptTL.Y)
ptTL.Y = ptBmpCellLoc_Right.Y;
if (ptBmpCellLoc_Right.Y > ptBR.Y)
ptBR.Y = ptBmpCellLoc_Right.Y;
//*/
cThisCell.eLeftType
= cThisCell.eRightType
= cThisCell.eBottomType
= enuLandscapeCellType.empty;
}
// create cell walls
for (int intCellCounter = 0; intCellCounter < cCells.Length; intCellCounter++)
{
classCaveCell cThisCaveCell = cCells[intCellCounter];
if (intCellCounter < cCells.Length -1)
{
cThisCaveCell.cRightWall.cMyCaveCell = cThisCaveCell;
cThisCaveCell.cRightWall.ptNext = cThisCaveCell.cNextCell.cRightWall.ptMine;
cThisCaveCell.cRightWall.dblNormal =classMath.cleanAngle( classMath.arcTan(cThisCaveCell.cRightWall.ptNext, cThisCaveCell.cRightWall.ptMine) + Math.PI / 2);
cThisCaveCell.cLeftWall.cMyCaveCell = cThisCaveCell;
cThisCaveCell.cLeftWall.ptNext = cThisCaveCell.cNextCell.cLeftWall.ptMine;
cThisCaveCell.cLeftWall.dblNormal = classMath.cleanAngle(classMath.arcTan(cThisCaveCell.cLeftWall.ptNext, cThisCaveCell.cLeftWall.ptMine) - Math.PI / 2);
}
if (intCellCounter == cCells.Length - 2)
{
cThisCaveCell.cBottomWall = new classCaveCell.classCaveCellWall();
cThisCaveCell.cBottomWall.cMyCaveCell = cThisCaveCell;
cThisCaveCell.cBottomWall.ptBottomLeft = cThisCaveCell.cLeftWall.ptNext;
cThisCaveCell.cBottomWall.ptBottomRight = cThisCaveCell.cRightWall.ptNext;
cThisCaveCell.cBottomWall.dblNormal = classMath.cleanAngle(classMath.arcTan(cThisCaveCell.cBottomWall.ptBottomRight , cThisCaveCell.cBottomWall.ptBottomLeft) - Math.PI / 2);
}
}
// set each wall's push-toward wall
for (int intCellCounter = 1; intCellCounter < cCells.Length; intCellCounter++)
{
classCaveCell cThisCell = cCells[intCellCounter];
if (intCellCounter < cCells.Length - 1)
{
{ // test left walls push towards each other
double dblAngleAwayFromThisTowardsPrevious = cThisCell.cPreviousCell.cLeftWall.dblNormal + Math.PI / 2;
double dblAngleAwayFromThisTowardsNext = cThisCell.cLeftWall.dblNormal - Math.PI / 2;
classMath.classDoubleCartesian dptPrev_Standard = new classMath.classDoubleCartesian(cThisCell.cLeftWall.ptMine.X + classLandscape.LandscapeCellWidth * Math.Cos(dblAngleAwayFromThisTowardsPrevious),
cThisCell.cLeftWall.ptMine.Y + classLandscape.LandscapeCellWidth * Math.Sin(dblAngleAwayFromThisTowardsPrevious));
classMath.classDoubleCartesian dptPrev_Alt = new classMath.classDoubleCartesian(dptPrev_Standard.X + classLandscape.LandscapeCellWidth * Math.Cos(cThisCell.cPreviousCell.cLeftWall.dblNormal),
dptPrev_Standard.Y + classLandscape.LandscapeCellWidth * Math.Sin(cThisCell.cPreviousCell.cLeftWall.dblNormal));
classMath.classDoubleCartesian dptNext_Standard = new classMath.classDoubleCartesian(cThisCell.cLeftWall.ptMine.X + classLandscape.LandscapeCellWidth * Math.Cos(dblAngleAwayFromThisTowardsNext),
cThisCell.cLeftWall.ptMine.Y + classLandscape.LandscapeCellWidth * Math.Sin(dblAngleAwayFromThisTowardsNext));
classMath.classDoubleCartesian dptNext_Alt = new classMath.classDoubleCartesian(dptNext_Standard.X + classLandscape.LandscapeCellWidth * Math.Cos(cThisCell.cLeftWall.dblNormal),
dptNext_Standard.Y + classLandscape.LandscapeCellWidth * Math.Sin(cThisCell.cLeftWall.dblNormal));
if (classMath.LinesIntersect(dptPrev_Standard, dptPrev_Alt, dptNext_Standard, dptNext_Alt, ref ptIntersection))
{
/// walls push towards each other
cThisCell.cLeftWall.cCellWallIPushTowards = cThisCell.cPreviousCell.cLeftWall;
if (cThisCell.cPreviousCell.cLeftWall.cCellWallIPushTowards != null)
{
System.Windows.Forms.MessageBox.Show("Problem : generateCave -> setting left wall push -> previous wall was already set");
}
else
cThisCell.cPreviousCell.cLeftWall.cCellWallIPushTowards = cThisCell.cLeftWall;
}
}
{ // test Right walls push towards each other
double dblAngleAwayFromThisTowardsPrevious = cThisCell.cPreviousCell.cRightWall.dblNormal - Math.PI / 2;
double dblAngleAwayFromThisTowardsNext = cThisCell.cRightWall.dblNormal + Math.PI / 2;
classMath.classDoubleCartesian dptPrev_Standard = new classMath.classDoubleCartesian(cThisCell.cRightWall.ptMine.X + classLandscape.LandscapeCellWidth * Math.Cos(dblAngleAwayFromThisTowardsPrevious),
cThisCell.cRightWall.ptMine.Y + classLandscape.LandscapeCellWidth * Math.Sin(dblAngleAwayFromThisTowardsPrevious));
classMath.classDoubleCartesian dptPrev_Alt = new classMath.classDoubleCartesian(dptPrev_Standard.X + classLandscape.LandscapeCellWidth * Math.Cos(cThisCell.cPreviousCell.cRightWall.dblNormal),
dptPrev_Standard.Y + classLandscape.LandscapeCellWidth * Math.Sin(cThisCell.cPreviousCell.cRightWall.dblNormal));
classMath.classDoubleCartesian dptNext_Standard = new classMath.classDoubleCartesian(cThisCell.cRightWall.ptMine.X + classLandscape.LandscapeCellWidth * Math.Cos(dblAngleAwayFromThisTowardsNext),
cThisCell.cRightWall.ptMine.Y + classLandscape.LandscapeCellWidth * Math.Sin(dblAngleAwayFromThisTowardsNext));
classMath.classDoubleCartesian dptNext_Alt = new classMath.classDoubleCartesian(dptNext_Standard.X + classLandscape.LandscapeCellWidth * Math.Cos(cThisCell.cNextCell.cRightWall.dblNormal),
dptNext_Standard.Y + classLandscape.LandscapeCellWidth * Math.Sin(cThisCell.cNextCell.cRightWall.dblNormal));
if (classMath.LinesIntersect(dptPrev_Standard, dptPrev_Alt, dptNext_Standard, dptNext_Alt, ref ptIntersection))
{
/// walls push towards each other
cThisCell.cRightWall.cCellWallIPushTowards = cThisCell.cPreviousCell.cRightWall;
if (cThisCell.cPreviousCell.cRightWall.cCellWallIPushTowards != null)
{
System.Windows.Forms.MessageBox.Show("Problem : generateCave -> setting Right wall push -> previous wall was already set");
}
else
cThisCell.cPreviousCell.cRightWall.cCellWallIPushTowards = cThisCell.cRightWall;
}
}
}
else
{ // bottom cell
}
}
/* /// draw bmpCellLoc
Size szBmpCells = new Size(ptBR.X - ptTL.X, ptBR.Y - ptTL.Y);
bmpCells = new Bitmap(szBmpCells.Width, szBmpCells.Height);
using (Graphics g = Graphics.FromImage(bmpCells))
{
g.FillRectangle(classPensAndBrushes.brWhite, new Rectangle(0, 0, bmpCells.Width, bmpCells.Height));
long lngColorincrement = classMath.convertBaseNtoInt(new int[] { 0, 256, 256, 256 }, 256) / cCells.Length;
for (int intCellCounter = 0; intCellCounter < cCells.Length - 1; intCellCounter++)
// for (int intCellCounter = 0; intCellCounter < 73; intCellCounter++)
{
int[] intColorCode = classMath.convertIntegerToBaseN(lngColorincrement * intCellCounter, 256, 4);
using (SolidBrush brCell = new SolidBrush(Color.FromArgb(255, intColorCode[1], intColorCode[2], intColorCode[3])))
{
Point[] ptPolygon = new Point[4];
ptPolygon[0] = convertGameWorldPointToBmpCellLocationPoints(cCells[intCellCounter].ptLeft);
ptPolygon[1] = convertGameWorldPointToBmpCellLocationPoints(cCells[intCellCounter].ptRight);
ptPolygon[2] = convertGameWorldPointToBmpCellLocationPoints(cCells[intCellCounter + 1].ptRight);
ptPolygon[3] = convertGameWorldPointToBmpCellLocationPoints(cCells[intCellCounter + 1].ptLeft);
for (int intPointcounter = 0; intPointcounter < ptPolygon.Length; intPointcounter++)
{
ptPolygon[intPointcounter].X -= ptTL.X;
ptPolygon[intPointcounter].Y -= ptTL.Y;
}
g.FillPolygon(brCell, ptPolygon);
}
}
}
bmpCells.Save("c:\\temp\\Caves\\Caves_(" + LandscapeCell.intMyIndex.ToString() + ").bmp");
//*/
classMath.classDoubleCartesian.bolClassLock = true;
}
}
public class classCaveCell
{
public double angle;
public double dblWidth;
public double dblDepth;
public enuLandscapeCellType eLeftType;
public enuLandscapeCellType eRightType;
public enuLandscapeCellType eBottomType;
public int intMyIndex;
public classCave cCave;
public classMath.classDoubleCartesian ptCenter;
public classCaveCellWall cLeftWall;
public classCaveCellWall cRightWall;
public classCaveCellWall cBottomWall;
public classCaveCell cNextCell;
public classCaveCell cPreviousCell;
public bool bolVisible;
classMath.classDoubleCartesian[] dptPoly;
public classCaveCell()
{
}
public bool pointIsInsideMe(classMath.classDoubleCartesian ptLoc)
{
if (intMyIndex < cCave.cCells.Length - 1)
{
if (dptPoly == null)
{
dptPoly = new classMath.classDoubleCartesian[4];
dptPoly[0] = cLeftWall.ptMine.Copy();
dptPoly[1] = cLeftWall.ptNext.Copy();
dptPoly[2] = cRightWall.ptNext.Copy();
dptPoly[3] = cRightWall.ptMine.Copy();
}
for (int intPtCounter = 0; intPtCounter < dptPoly.Length; intPtCounter++)
{
double dblDifference = dptPoly[intPtCounter].X - ptLoc.X;
if (Math.Abs(dblDifference) > cCave.LandscapeCell.cLandscape.dblRealWidth / 2)
{
if (dblDifference > 0)
dptPoly[intPtCounter].X -= cCave.LandscapeCell.cLandscape.dblRealWidth;
else
dptPoly[intPtCounter].X += cCave.LandscapeCell.cLandscape.dblRealWidth;
}
}
return classMath.PointInPolygon(ptLoc, dptPoly);
}
else
return false;
}
public class classCaveCellWall
{
public classCaveCellWall()
{
_ptMine.bolLock
= ptNext.bolLock
= false;
}
public classCaveCell cMyCaveCell;
public classMath.classDoubleCartesian _ptMine = new classMath.classDoubleCartesian();
public classMath.classDoubleCartesian ptMine
{
get { return _ptMine; }
set
{
_ptMine = value;
}
}
public classMath.classDoubleCartesian _ptNext = new classMath.classDoubleCartesian();
public classMath.classDoubleCartesian ptNext
{
get { return _ptNext; }
set
{
_ptNext = value;
}
}
classMath.classDoubleCartesian _ptBottomLeft;
public classMath.classDoubleCartesian ptBottomLeft
{
get { return _ptBottomLeft; }
set
{
_ptBottomLeft = value;
}
}
classMath.classDoubleCartesian _ptBottomRight;
public classMath.classDoubleCartesian ptBottomRight
{
get { return _ptBottomRight; }
set
{
_ptBottomRight = value;
}
}
public classCaveCellWall cCellWallIPushTowards;
public static double dblStandardPush = classLandscape.LandscapeCellWidth / 1000.0;
public static int intCounter;
classMath.classDoubleCartesian dptIntersection;
public void Push(ref classMath.classDoubleCartesian ptLoc, double dblRadiusObject) { Push(ref ptLoc, dblRadiusObject, false); }
public void Push(ref classMath.classDoubleCartesian ptLoc, double dblRadiusObject, bool bolForceWedge)
{
//double dblDistanceToLeft = classMath.distanceBetweenTwoPoints(ptLoc, ptMine);
//double dblDistanceToRight = classMath.distanceBetweenTwoPoints(ptLoc, ptNext);
//if ((ptLoc.X + dblRadiusObject <= (ptMine.X < ptNext.X ? ptMine.X : ptNext.X)
// || ptLoc.X - dblRadiusObject >= (ptMine.X > ptNext.X ? ptMine.X : ptNext.X)
// || ptLoc.Y + dblRadiusObject <= (ptMine.Y < ptNext.Y ? ptMine.Y : ptNext.Y))
// && dblDistanceToLeft > dblRadiusObject
// && dblDistanceToRight > dblRadiusObject)
//{
// return;
//}
intCounter++;
if (intCounter > 3)
{
WedgeObject(ref ptLoc, dblRadiusObject);
return;
}
// create a second pt in Normal direction
//// find point of intersection b/w this line normal to landscape and landscape
dptIntersection = dptIntersection = new classMath.classDoubleCartesian();
if (this == cMyCaveCell.cBottomWall)
classMath.LineIntersectsCircle(ptLoc, dblRadiusObject, ptBottomLeft, ptBottomRight, ref dptIntersection);
else
classMath.LineIntersectsCircle(ptLoc, dblRadiusObject, ptMine, ptNext, ref dptIntersection);
// calculate distance between the dptIntersection and ptLoc
double dblDistance = Math.Floor(classMath.distanceBetweenTwoPoints(ptLoc, dptIntersection));
/// calculate height of line at that location X
//double dblYatX = dblM * ptTemp.X + dblB;
dblStandardPush = 0.05 * classLandscape.LandscapeCellWidth;
if (dblDistance <= dblRadiusObject)
{
if (bolForceWedge)
{
WedgeObject(ref ptLoc, dblRadiusObject);
}
else
{
classMath.classDoubleCartesian ptNew = new classMath.classDoubleCartesian();
ptNew.X = dptIntersection.X + (dblRadiusObject + dblStandardPush) * Math.Cos(dblNormal);
ptNew.Y = dptIntersection.Y + (dblRadiusObject + dblStandardPush) * Math.Sin(dblNormal);
if (ptNew.Y > ptLoc.Y)
classLandscape.frmMain.Refresh();
ptLoc = ptNew;
if (cCellWallIPushTowards != null)
{
cCellWallIPushTowards.Push(ref ptLoc, dblRadiusObject, true);
}
}
}
}
void WedgeObject(ref classMath.classDoubleCartesian ptLoc, double dblRadiusObject)
{
/// code copied from landscape fails here
//dblRadiusObject *= 1.05;
//classMath.classDoubleCartesian ptCommon = ptMine;
//double dblAngleNeaghbour = classMath.cleanAngle(cellLeft.dblNormal - Math.PI / 2);
//double dblMyAngle = classMath.cleanAngle(dblNormal + Math.PI / 2);
//if (dblNormal > 1.5 * Math.PI)
//{
// ptCommon = ptNext;
// dblAngleNeaghbour = classMath.cleanAngle(cellRight.dblNormal + Math.PI / 2);
// dblMyAngle = classMath.cleanAngle(dblNormal - Math.PI / 2);
//}
//double dblAngleCenterLine = (dblMyAngle + dblAngleNeaghbour) / 2;
//double dblTangentToCircle = Math.Abs(dblMyAngle - dblAngleCenterLine);
//double dblNormalToCircle = dblTangentToCircle + Math.PI / 2;
//double dblASideofWedgeTriangle = dblRadiusObject * Math.Abs(Math.Sin(dblNormalToCircle) / Math.Tan(dblTangentToCircle));
//double dblASideOfCircleTriangle = dblRadiusObject * Math.Abs(Math.Cos(dblNormalToCircle));
//double dblTotalDistance = dblASideOfCircleTriangle + dblASideofWedgeTriangle;
//ptLoc.X = ptCommon.X + dblTotalDistance * Math.Cos(dblAngleCenterLine);
//ptLoc.Y = ptCommon.Y + dblTotalDistance * Math.Sin(dblAngleCenterLine);
}
public double dblNormal;
}
}
//public class classCaveCoordinate
//{
// public double Shift;
// public double Depth;
//}
}
//public classMath.classDoubleCartesian ConvertPoint_CaveToCartesian(classCaveCoordinate ptCaveLoc)
//{
// classMath.classDoubleCartesian ptRetVal = new classMath.classDoubleCartesian();
// if (ptCaveLoc == null)
// return null;
// int intCellIndex = (int)Math.Floor(ptCaveLoc.Depth / classLandscape.LandscapeCellWidth);
// if (intCellIndex >= 0 && intCellIndex < cCells.Length)
// {
// classCaveCell cThisCell = cCells[intCellIndex];
// double dblDepthFromCenter = ptCaveLoc.Depth - intCellIndex * classLandscape.LandscapeCellWidth;
// classMath.classDoubleCartesian ptReference = new classMath.classDoubleCartesian(cThisCell.ptCenter.X + dblDepthFromCenter * Math.Cos(cThisCell.angle),
// cThisCell.ptCenter.Y + dblDepthFromCenter * Math.Sin(cThisCell.angle));
// int intSign = ptCaveLoc.Shift > 0 ? -1: 1;
// ptRetVal.X = ptReference.X + Math.Abs(ptCaveLoc.Shift) * Math.Cos(cThisCell.angle + intSign * Math.PI / 2);
// ptRetVal.Y = ptReference.Y + Math.Abs(ptCaveLoc.Shift) * Math.Sin(cThisCell.angle + intSign * Math.PI / 2);
// classLandscape.frmMain.Text += "to Cartesian -> (" + ptRetVal.X.ToString("f2") + ", " + ptRetVal.Y.ToString("f2") + ")";
// return ptRetVal;
// }
// else
// System.Windows.Forms.MessageBox.Show("Error : ConvertPoint_CaveToCartesian -> cave cell does not exist");
// return null;
//}
//public classCaveCoordinate ConvertPoint_CartesianToCave(classMath.classDoubleCartesian ptCartesianLoc, int intApproximateCellIndex)
//{
// int intSearchVariance = 2;
// classCaveCell cThisCell = cCells[intApproximateCellIndex];
// for (int intShiftUpCounter = 0; intShiftUpCounter < intSearchVariance && cThisCell.cPreviousCell != null; intShiftUpCounter++)
// cThisCell = cThisCell.cPreviousCell;
// int intSearchCounter = 0;
// classMath.classDoubleCartesian ptAlternate = new classMath.classDoubleCartesian();
// classMath.classDoubleCartesian ptIntersection = new classMath.classDoubleCartesian();
// classMath.classDoubleRectangle recTestZone = new classMath.classDoubleRectangle();
// while (intSearchCounter < 2 * intSearchVariance)
// {
// classMath.classDoubleCartesian[] ptPolygon = { cThisCell.cLeftWall.ptMine, cThisCell.cLeftWall.ptNext, cThisCell.cRightWall.ptNext, cThisCell.cRightWall.ptMine, cThisCell.cLeftWall.ptMine };
// if (classMath.PointInPolygon(ptCartesianLoc, ptPolygon))
// {
// ptAlternate.X = ptCartesianLoc.X + classLandscape.LandscapeCellWidth * Math.Cos(cThisCell.angle+Math.PI/2);
// ptAlternate.Y = ptCartesianLoc.Y + classLandscape.LandscapeCellWidth * Math.Sin(cThisCell.angle+Math.PI/2);
// classMath.LinesIntersect(ptCartesianLoc, ptAlternate, cThisCell.ptCenter, cThisCell.cNextCell.ptCenter, ref ptIntersection);
// double dblAngleBetweenIntersectionAndPoint = classMath.arcTan(ptCartesianLoc, ptIntersection);
// double dblDeltaTheta = classMath.cleanAngle(dblAngleBetweenIntersectionAndPoint - cThisCell.angle);
// double dblAbsoluteX = classMath.distanceBetweenTwoPoints(ptIntersection, ptCartesianLoc);
// classCaveCoordinate ptRetVal = new classCaveCoordinate();
// ptRetVal.Shift = dblAbsoluteX * ((dblDeltaTheta > Math.PI) ? 1 : -1);
// ptRetVal.Depth = (cThisCell.intMyIndex) * classLandscape.LandscapeCellWidth + classMath.distanceBetweenTwoPoints(cThisCell.ptCenter, ptIntersection);
// classLandscape.frmMain.Text = "Cartesian (" + ptCartesianLoc.X.ToString("f2") + ", " + ptCartesianLoc.Y.ToString("f2") + ") to cave[" + cThisCell.intMyIndex.ToString() + "] (" + ptRetVal.Shift.ToString("f2") + ", " + ptRetVal.Depth.ToString("f2") + ") :::";
// return ptRetVal;
// }
// intSearchCounter++;
// cThisCell = cThisCell.cNextCell;
// }
// return null;
//}