You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
676 lines
24 KiB
676 lines
24 KiB
using AX.MessageSystem; |
|
using System; |
|
using System.Collections; |
|
using System.Collections.Generic; |
|
using UnityEngine; |
|
using UnityEngine.EventSystems; |
|
using UnityEngine.UI; |
|
|
|
[Serializable] |
|
public class FireSettingData |
|
{ |
|
public long id; |
|
public string name; |
|
public string rsw; |
|
public string pos; |
|
public int type; |
|
public int time; |
|
public List<Vector3> pathPointList; |
|
public string temperature; //火焰温度 |
|
public string radiation; //热辐射 |
|
} |
|
public class FireSettingPanel : ResourceLoadPanel<FireSettingPanel> |
|
{ |
|
public InputField RSWInput; |
|
public InputField PosInput; |
|
public InputField WDInput; |
|
public InputField RFSInput; |
|
public Toggle StraightSpread; |
|
public Toggle AreaSpread; |
|
public Toggle AroundSpread; |
|
public InputField TimeInput; |
|
public Text ErrorText; |
|
public Button ResetBtn; |
|
public Button SaveBtn; |
|
public Button CloseBtn; |
|
public List<Vector3> PathPointList = new List<Vector3>(); |
|
|
|
private RaycastHit hit; |
|
private Ray ray; |
|
public Vector3 startPosition = Vector3.zero;//定义一个Vector3,用来存储鼠标点击的位置 |
|
private Vector3 endPosition = Vector3.zero;//定义一个Vector3,用来存储鼠标点击的位置 |
|
public LayerMask layerMask = -1; |
|
public Transform lineObjParent; |
|
public Transform lineObj; |
|
private GameObject lineObjChild; |
|
private GameObject linePrefab; |
|
|
|
private Line line1 = new Line();//多边形最后一条边 |
|
private Line line2 = new Line();//多边形除最后一条边的其他各边 |
|
private Line line3 = new Line();//多边形倒数第二边 |
|
private FireSettingData NowData = new FireSettingData(); |
|
private GameObject NowObj; |
|
// Use this for initialization |
|
void Start() |
|
{ |
|
RSWInput.onValueChanged.AddListener(RSWInput_valueChanged); |
|
PosInput.onValueChanged.AddListener(PosInput_valueChanged); |
|
TimeInput.onValueChanged.AddListener(TimeInput_valueChanged); |
|
WDInput.onValueChanged.AddListener(WDInput_valueChanged); |
|
RFSInput.onValueChanged.AddListener(RFSInput_valueChanged); |
|
StraightSpread.onValueChanged.AddListener(StraightSpread_valueChanged); |
|
AreaSpread.onValueChanged.AddListener(AreaSpread_valueChanged); |
|
AroundSpread.onValueChanged.AddListener(AroundSpread_valueChanged); |
|
ResetBtn.onClick.AddListener(ResetBtn_Click); |
|
SaveBtn.onClick.AddListener(SaveBtn_Click); |
|
CloseBtn.onClick.AddListener(CloseBtn_Click); |
|
MessageDispatcher.AddListener("SelectChange", selectchange); |
|
} |
|
private void OnDestroy() |
|
{ |
|
MessageDispatcher.RemoveListener("SelectChange", selectchange); |
|
} |
|
|
|
private void selectchange(IMessage obj) |
|
{ |
|
gameObject.SetActive(false); |
|
} |
|
|
|
public void AddRecordEventFire(GameObject obj, FireSettingData data) |
|
{ |
|
if (ReplaySetting.PlayStatus == PlayStatus.isEditor && RecordManager.Instance.recordStatus == RecordStatus.normal) |
|
{ |
|
var eventData = new EventData(); |
|
eventData.time = RecordManager.Instance.RecordTimer; |
|
eventData.cloneObjType = obj.GetComponent<CloneGameObjInfo>().gameObjType; |
|
eventData.eventType = RecordEventType.Fire; |
|
eventData.json = JsonUtility.ToJson(data); |
|
|
|
RecordManager.Instance.jsonData.eventDataList.Add(eventData); |
|
} |
|
} |
|
public void AddRecordEventFireReset(GameObject obj, FireSettingData data) |
|
{ |
|
if (ReplaySetting.PlayStatus == PlayStatus.isEditor && RecordManager.Instance.recordStatus == RecordStatus.normal) |
|
{ |
|
var eventData = new EventData(); |
|
eventData.time = RecordManager.Instance.RecordTimer; |
|
eventData.cloneObjType = obj.GetComponent<CloneGameObjInfo>().gameObjType; |
|
eventData.eventType = RecordEventType.FireReset; |
|
eventData.json = JsonUtility.ToJson(data); |
|
|
|
RecordManager.Instance.jsonData.eventDataList.Add(eventData); |
|
} |
|
} |
|
public void SettingFire(GameObject Fire) |
|
{ |
|
NowObj = Fire; |
|
NowData = Fire.GetComponent<FireControl>().MyData; |
|
RSWInput.text = NowData.rsw; |
|
PosInput.text = NowData.pos; |
|
TimeInput.text = NowData.time.ToString(); |
|
WDInput.text = NowData.temperature; |
|
RFSInput.text = NowData.radiation; |
|
StraightSpread.isOn = NowData.type == 1; |
|
AreaSpread.isOn = NowData.type == 2; |
|
AroundSpread.isOn = NowData.type == 3; |
|
PathPointList = NowData.pathPointList; |
|
ErrorText.text = ""; |
|
if (PathPointList.Count > 0) |
|
{ |
|
GetLineObj(); |
|
//Debug.Log("Line"+lineObj.name); |
|
startPosition = PathPointList[PathPointList.Count - 1]; |
|
} |
|
else |
|
{ |
|
startPosition = Fire.transform.position; |
|
} |
|
} |
|
private void CloseBtn_Click() |
|
{ |
|
gameObject.SetActive(false); |
|
//隐藏或删除路径 |
|
NowData = null; |
|
if (lineObj != null) |
|
lineObj.gameObject.SetActive(false); |
|
lineObj = null; |
|
NowObj = null; |
|
} |
|
|
|
public void SaveBtn_Click() |
|
{ |
|
NowObj.GetComponent<FireControl>().SetTemperatureText(); |
|
NowObj.GetComponent<FireControl>().SetRadiationText(); |
|
|
|
if (!StraightSpread.group.AnyTogglesOn()) |
|
{ |
|
ErrorText.text = "请先选择蔓延方式!"; |
|
return; |
|
} |
|
if (string.IsNullOrEmpty(TimeInput.text)) |
|
{ |
|
ErrorText.text = "请输入时间!"; |
|
return; |
|
} |
|
//if (NowData.time == 0) |
|
//{ |
|
// ErrorText.text = "请输入正整数时间!"; |
|
// return; |
|
//} |
|
if (NowData.pathPointList.Count == 0) |
|
{ |
|
ErrorText.text = "请划定蔓延区域!"; |
|
return; |
|
} |
|
|
|
if (NowObj.GetComponent<FireSpreadCtrl>().isSpreading) |
|
{ |
|
ResourceLoadWindow.Instance.LoadTipWindow("当前火焰正在蔓延,是否结束并开始新的蔓延?", |
|
() => |
|
{ |
|
AddRecordEventFire(NowObj, NowData); |
|
if (ReplaySetting.PlayStatus != PlayStatus.isReplay) |
|
NowObj.GetComponent<FireSpreadCtrl>().Spread(NowData); |
|
CloseBtn_Click(); |
|
}, |
|
() => CloseBtn_Click()); |
|
return; |
|
} |
|
AddRecordEventFire(NowObj, NowData); |
|
if (ReplaySetting.PlayStatus != PlayStatus.isReplay) |
|
NowObj.GetComponent<FireSpreadCtrl>().Spread(NowData); |
|
CloseBtn_Click(); |
|
} |
|
|
|
private void ResetBtn_Click() |
|
{ |
|
ResetPath(); |
|
} |
|
|
|
private void PosInput_valueChanged(string value) |
|
{ |
|
NowData.pos = value; |
|
} |
|
|
|
private void RSWInput_valueChanged(string value) |
|
{ |
|
NowData.rsw = value; |
|
} |
|
private void WDInput_valueChanged(string value) |
|
{ |
|
NowData.temperature = value; |
|
} |
|
private void RFSInput_valueChanged(string value) |
|
{ |
|
NowData.radiation = value; |
|
} |
|
private void AroundSpread_valueChanged(bool Ison) |
|
{ |
|
if (Ison) |
|
{ |
|
if (NowData.type != 3) |
|
ResetLinePath(); |
|
TimeInput.interactable = true; |
|
NowData.type = 3; |
|
} |
|
else |
|
{ |
|
if (!StraightSpread.group.AnyTogglesOn()) |
|
{ |
|
TimeInput.interactable = false; |
|
NowData.type = 0; |
|
} |
|
} |
|
} |
|
|
|
private void AreaSpread_valueChanged(bool Ison) |
|
{ |
|
if (Ison) |
|
{ |
|
if (NowData.type != 2) |
|
ResetLinePath(); |
|
TimeInput.interactable = true; |
|
NowData.type = 2; |
|
} |
|
else |
|
{ |
|
if (!StraightSpread.group.AnyTogglesOn()) |
|
{ |
|
TimeInput.interactable = false; |
|
NowData.type = 0; |
|
} |
|
} |
|
} |
|
|
|
private void StraightSpread_valueChanged(bool Ison) |
|
{ |
|
if (Ison) |
|
{ |
|
if (NowData.type != 1) |
|
ResetLinePath(); |
|
TimeInput.interactable = true; |
|
NowData.type = 1; |
|
} |
|
else |
|
{ |
|
if (!StraightSpread.group.AnyTogglesOn()) |
|
{ |
|
TimeInput.interactable = false; |
|
NowData.type = 0; |
|
} |
|
} |
|
} |
|
|
|
private void TimeInput_valueChanged(string value) |
|
{ |
|
if (string.IsNullOrEmpty(value)) |
|
return; |
|
int time = int.Parse(value); |
|
if (time < 0) |
|
{ |
|
ErrorText.text = "请输入正整数时间!"; |
|
TimeInput.text = ""; |
|
} |
|
else |
|
{ |
|
NowData.time = time; |
|
ErrorText.text = ""; |
|
} |
|
} |
|
private void ResetPath() |
|
{ |
|
PathPointList.Clear(); |
|
ResetLinePath(); |
|
|
|
//重置路径时,如果是已经蔓延过一次及存在蔓延出来的火,重置删除蔓延路径的同时,删除蔓延出来的火 |
|
Transform pfire = GameObject.Find("P_AllParent").transform.Find("P_Disaster/P_SpreadFire"); |
|
foreach (Transform child in pfire) |
|
{ |
|
if (child.GetComponent<SpreadFire>() && child.GetComponent<SpreadFire>().SourceId == NowData.id) |
|
{ |
|
Destroy(child.gameObject); |
|
} |
|
} |
|
AddRecordEventFireReset(NowObj, NowData); |
|
NowObj.GetComponent<FireSpreadCtrl>().Reset(); |
|
} |
|
|
|
private void ResetLinePath() |
|
{ |
|
GetLineObj(); |
|
//重置路线 |
|
if (lineObj != null) |
|
{ |
|
foreach (Transform child in lineObj) |
|
{ |
|
Destroy(child.gameObject); |
|
} |
|
PathPointList.Clear(); |
|
startPosition = EntitiesManager.Instance.GetEntityByID(NowData.id).transform.position; |
|
} |
|
} |
|
|
|
private void GetLineObj() |
|
{ |
|
if (lineObjParent == null) |
|
{ |
|
lineObjParent = GameObject.Find("P_AllParent").transform.Find("P_Disaster/P_FireLine"); |
|
} |
|
foreach (Transform t in lineObjParent) |
|
{ |
|
if (t.name == NowData.id.ToString()) |
|
{ |
|
lineObj = t; |
|
if (!lineObj.gameObject.activeSelf) |
|
{ |
|
lineObj.gameObject.SetActive(true); |
|
} |
|
} |
|
else |
|
{ |
|
if (t.gameObject.activeSelf) |
|
{ |
|
t.gameObject.SetActive(false); |
|
} |
|
} |
|
} |
|
} |
|
|
|
// Update is called once per frame |
|
void Update() |
|
{ |
|
if (gameObject.activeSelf) |
|
{ |
|
if ((StraightSpread.isOn || AreaSpread.isOn || AroundSpread.isOn) && InputManager.cloneObjType == CloneObjType.None) |
|
{ |
|
if (Input.GetMouseButtonDown(0) && !EventSystem.current.IsPointerOverGameObject()) |
|
{ |
|
ray = Camera.main.ScreenPointToRay(Input.mousePosition); |
|
if (Physics.Raycast(ray, out hit, Mathf.Infinity)) |
|
{ |
|
//if (hit.transform.gameObject.layer == LayerMask.NameToLayer("PathFinding") |
|
// || hit.transform.gameObject.layer == LayerMask.NameToLayer("shineiFloor")) |
|
if (hit.transform.GetComponent<CloneableEnums>() && |
|
hit.transform.GetComponent<CloneableEnums>().CloneableTypes.Contains(CloneObjType.FireNormal) |
|
) |
|
{ |
|
if (NowObj.GetComponent<CloneGameObjInfo>().gameObjType == CloneObjType.FireHuge) |
|
{ |
|
if (Mathf.Abs(hit.transform.position.y - NowObj.transform.position.y) > 7) |
|
return; |
|
} |
|
else |
|
{ |
|
if (Mathf.Abs(hit.transform.position.y - NowObj.transform.position.y) > 3) |
|
return; |
|
} |
|
if (PathPointList.Count == 0)//第一次设置或重置后再设置蔓延路径的情况 |
|
{ |
|
if (StraightSpread.isOn || AreaSpread.isOn) |
|
{ |
|
PathPointList.Add(startPosition); |
|
} |
|
else if (AroundSpread.isOn) |
|
{ |
|
startPosition = hit.point; |
|
} |
|
|
|
CloneFireSpreadPath(); |
|
} |
|
else |
|
{ |
|
startPosition = PathPointList[PathPointList.Count - 1]; |
|
|
|
CloneFireSpreadPath(); |
|
} |
|
} |
|
} |
|
} |
|
|
|
} |
|
} |
|
} |
|
private void CloneFireSpreadPath() |
|
{ |
|
bool isintersection1 = false; |
|
bool isintersection2 = false; |
|
|
|
PathPointList.Add(hit.point); |
|
|
|
endPosition = hit.point; |
|
|
|
if (startPosition == endPosition) |
|
{ |
|
return; |
|
} |
|
|
|
Vector3 tempPos = (startPosition + endPosition) / 2; |
|
if (linePrefab == null) |
|
linePrefab = Resources.Load<GameObject>("Prefab/Diaster/FireSpreadLine"); |
|
lineObjChild = Instantiate(linePrefab, tempPos, Quaternion.identity) as GameObject; |
|
if (lineObjParent == null) |
|
lineObjParent = GameObject.Find("P_AllParent").transform.Find("P_Disaster/P_FireLine"); |
|
if (lineObj == null) |
|
lineObj = new GameObject().transform; |
|
lineObj.name = NowData.id.ToString(); |
|
lineObj.SetParent(lineObjParent); |
|
lineObjChild.transform.parent = lineObj.transform; |
|
lineObjChild.transform.up = (-(endPosition - startPosition)).normalized;//改变线条的朝向 |
|
float distance = Vector3.Distance(startPosition, endPosition);//计算两点的距离 |
|
lineObjChild.transform.localScale = new Vector3(5f, distance * 18, 5f);//延长线条,连接两点。 |
|
if (StraightSpread.isOn) |
|
{ |
|
startPosition = endPosition; |
|
} |
|
|
|
//如果是区域蔓延方式或四周蔓延,在顶点数大于2的情况下,画出终点与起始点连接成的边 |
|
if (AreaSpread.isOn || AroundSpread.isOn) |
|
{ |
|
if (PathPointList.Count > 2) |
|
{ |
|
line1.Start = new Vector2(endPosition.x, endPosition.z); |
|
line1.End = new Vector2(PathPointList[0].x, PathPointList[0].z); |
|
|
|
line3.Start = new Vector2(PathPointList[PathPointList.Count - 2].x, PathPointList[PathPointList.Count - 2].z); |
|
line3.End = new Vector2(endPosition.x, endPosition.z); |
|
for (int i = 0; i < PathPointList.Count; i++) |
|
{ |
|
if ((i + 1) <= (PathPointList.Count - 1)) |
|
{ |
|
line2.Start = new Vector2(PathPointList[i].x, PathPointList[i].z); |
|
line2.End = new Vector2(PathPointList[i + 1].x, PathPointList[i + 1].z); |
|
|
|
isintersection1 = CheckTwoLineCrose(line1, line2, PathPointList); |
|
|
|
if (isintersection1) |
|
{ |
|
break; |
|
} |
|
} |
|
} |
|
|
|
for (int i = 0; i < PathPointList.Count; i++) |
|
{ |
|
if ((i + 1) <= (PathPointList.Count - 1)) |
|
{ |
|
line2.Start = new Vector2(PathPointList[i].x, PathPointList[i].z); |
|
line2.End = new Vector2(PathPointList[i + 1].x, PathPointList[i + 1].z); |
|
|
|
if ((line3.Start != line2.Start) && line3.End != line2.End)//排除line3和自己比 |
|
{ |
|
isintersection2 = CheckTwoLineCrose(line3, line2, PathPointList); |
|
} |
|
|
|
if (isintersection2) |
|
{ |
|
break; |
|
} |
|
} |
|
} |
|
|
|
if (!isintersection1 && !isintersection2) |
|
{ |
|
Vector3 tempPos1 = (endPosition + PathPointList[0]) / 2; |
|
lineObjChild = Instantiate(linePrefab, tempPos1, Quaternion.identity) as GameObject; |
|
lineObjChild.transform.parent = lineObj.transform; |
|
lineObjChild.transform.up = (-(PathPointList[0] - endPosition)).normalized; |
|
float distance1 = Vector3.Distance(endPosition, PathPointList[0]); |
|
lineObjChild.transform.localScale = new Vector3(5f, distance1 * 18, 5f); |
|
|
|
startPosition = endPosition; |
|
|
|
if (PathPointList.Count > 3)//如果是区域蔓延方式或四周蔓延,要删除前一次终点到起始点的边 |
|
Destroy(lineObj.transform.GetChild(lineObj.transform.childCount - 3).gameObject); |
|
} |
|
else |
|
{ |
|
Destroy(lineObj.transform.GetChild(lineObj.transform.childCount - 1).gameObject); |
|
PathPointList.RemoveAt(PathPointList.Count - 1); |
|
//messageBox.GetComponent<MessageTool>().showMessage(ShowMessageType.prompt, "提示信息", "不能形成多边形"); |
|
ResourceLoadWindow.Instance.LoadTextHintWindow("不能形成多边形", 1f); |
|
} |
|
} |
|
} |
|
} |
|
|
|
struct Line |
|
{ |
|
public Vector2 Start, End; |
|
} |
|
|
|
/// <summary> |
|
/// 判断直线2的两点是否在直线1的两边。 |
|
/// </summary> |
|
/// <param name="line1">直线1</param> |
|
/// <param name="line2">直线2</param> |
|
/// <returns></returns> |
|
private bool CheckCrose(Line line1, Line line2) |
|
{ |
|
Vector2 v1 = new Vector2(); |
|
Vector2 v2 = new Vector2(); |
|
Vector2 v3 = new Vector2(); |
|
|
|
v1.x = line2.Start.x - line1.End.x; |
|
v1.y = line2.Start.y - line1.End.y; |
|
|
|
v2.x = line2.End.x - line1.End.x; |
|
v2.y = line2.End.y - line1.End.y; |
|
|
|
v3.x = line1.Start.x - line1.End.x; |
|
v3.y = line1.Start.y - line1.End.y; |
|
|
|
return (CrossMul(v1, v3) * CrossMul(v2, v3) <= 0); |
|
|
|
} |
|
/// <summary> |
|
/// 判断两条线段是否相交,若相交且交点不是端点。 |
|
/// </summary> |
|
/// <param name="line1">线段1</param> |
|
/// <param name="line2">线段2</param> |
|
/// <returns>相交返回真,否则返回假。</returns> |
|
private bool CheckTwoLineCrose(Line line1, Line line2, List<Vector3> PathPointList) |
|
{ |
|
//return CheckCrose(line1, line2) && CheckCrose(line2, line1); |
|
bool isintersection = CheckCrose(line1, line2) && CheckCrose(line2, line1); |
|
Vector2 intersection = GetIntersection(line1.Start, line1.End, line2.Start, line2.End); |
|
bool dengYuDuanDian = true; |
|
|
|
if (intersection != line1.Start |
|
&& intersection != line1.End |
|
&& intersection != line2.Start |
|
&& intersection != line2.End) |
|
{ |
|
dengYuDuanDian = false; |
|
} |
|
|
|
if (isintersection && !dengYuDuanDian) |
|
{ |
|
return true; |
|
} |
|
else |
|
{ |
|
return false; |
|
} |
|
} |
|
/// <summary> |
|
/// 计算两个向量的叉乘。 |
|
/// </summary> |
|
/// <param name="pt1"></param> |
|
/// <param name="pt2"></param> |
|
/// <returns></returns> |
|
private float CrossMul(Vector2 pt1, Vector2 pt2) |
|
{ |
|
return pt1.x * pt2.y - pt1.y * pt2.x; |
|
} |
|
|
|
/// <summary> |
|
/// 求两条线段的交点 |
|
/// </summary> |
|
/// <param name="a">线段1起点坐标</param> |
|
/// <param name="b">线段1终点坐标</param> |
|
/// <param name="c">线段2起点坐标</param> |
|
/// <param name="d">线段2终点坐标</param> |
|
/// <param name="intersection">相交点坐标</param> |
|
private Vector2 GetIntersection(Vector2 a, Vector2 b, Vector2 c, Vector2 d) |
|
{ |
|
Vector2 intersection = new Vector2(); |
|
intersection.x = ((b.x - a.x) * (c.x - d.x) * (c.y - a.y) - c.x * (b.x - a.x) * (c.y - d.y) + a.x * (b.y - a.y) * (c.x - d.x)) |
|
/ ((b.y - a.y) * (c.x - d.x) - (b.x - a.x) * (c.y - d.y)); |
|
intersection.y = ((b.y - a.y) * (c.y - d.y) * (c.x - a.x) - c.y * (b.y - a.y) * (c.x - d.x) + a.y * (b.x - a.x) * (c.y - d.y)) |
|
/ ((b.x - a.x) * (c.y - d.y) - (b.y - a.y) * (c.x - d.x)); |
|
|
|
if ((intersection.x - a.x) * (intersection.x - b.x) <= 0 |
|
&& (intersection.x - c.x) * (intersection.x - d.x) <= 0 |
|
&& (intersection.y - a.y) * (intersection.y - b.y) <= 0 |
|
&& (intersection.y - c.y) * (intersection.y - d.y) <= 0) |
|
{ |
|
Debug.Log("线段相交于点(" + intersection.x + "," + intersection.y + ")!"); |
|
return intersection; //相交 |
|
} |
|
else |
|
{ |
|
return Vector2.zero; |
|
} |
|
} |
|
|
|
// wn_PnPoly(): winding number test for a point in a polygon |
|
// Input: point = a point, |
|
// polygon = anticlockwise vertex points of a polygon polygon[n] |
|
// Return: wn = the winding number (=0 only when P is outside) |
|
// See:"http://geomalgorithms.com/a03-_inclusion.html" |
|
int wn_PnPoly(List<Vector2> polygon, Vector2 point) |
|
{ |
|
//polygon顶点的X,Y数组 |
|
float[] polyline = new float[2 * polygon.Count]; |
|
for (int i = 0; i < polygon.Count; i++) |
|
{ |
|
polyline[i + i] = polygon[i].x; |
|
polyline[i + i + 1] = polygon[i].y; |
|
} |
|
|
|
float maxx = 0, minx = 0, maxy = 0, miny = 0; |
|
int pointcount = 0; |
|
if (polyline != null) |
|
{ |
|
pointcount = polyline.Length / 2; |
|
maxx = minx = polyline[0]; |
|
maxy = miny = polyline[1]; |
|
for (int i = 0; i < pointcount; i++) |
|
{ |
|
if (maxx < polyline[i + i]) |
|
maxx = polyline[i + i]; |
|
if (minx > polyline[i + i]) |
|
minx = polyline[i + i]; |
|
if (maxy < polyline[i + i + 1]) |
|
maxy = polyline[i + i + 1]; |
|
if (miny > polyline[i + i + 1]) |
|
miny = polyline[i + i + 1]; |
|
} |
|
} |
|
|
|
int n = polygon.Count; |
|
int wn = 0; // the winding number counter |
|
|
|
//首先判断是否在多边形的外框范围内 |
|
if (point.x < minx || point.x > maxx |
|
|| point.y < miny || point.y > maxy) |
|
{ |
|
return 0; |
|
} |
|
else |
|
{ |
|
// loop through all edges of the polygon |
|
for (int i = 0; i < n; i++) |
|
{ // edge from polygon[i] to polygon[i+1] |
|
if (polygon[i].y <= point.y) |
|
{ // start y <= P.y |
|
if (polygon[(i + 1) % n].y > point.y) // an upward crossing |
|
if (isLeft(polygon[i], polygon[(i + 1) % n], point) > 0) // P left of edge |
|
++wn; // have a valid up intersect |
|
} |
|
else |
|
{ // start y > P.y (no test needed) |
|
if (polygon[(i + 1) % n].y <= point.y) // a downward crossing |
|
if (isLeft(polygon[i], polygon[(i + 1) % n], point) < 0) // P right of edge |
|
--wn; // have a valid down intersect |
|
} |
|
} |
|
return wn; |
|
} |
|
} |
|
|
|
//isLeft(): tests if a point is Left|On|Right of an infinite line. |
|
//Input: three points P0, P1, and P2 |
|
//Return: >0 for P2 left of the line through P0 and P1 |
|
// =0 for P2 on the line |
|
// <0 for P2 right of the line |
|
// See:"http://geomalgorithms.com/a03-_inclusion.html":Algorithm 1 "Area of Triangles and Polygons" |
|
// Or "http://geomalgorithms.com/a01-_area.html" |
|
|
|
float isLeft(Vector2 P0, Vector2 P1, Vector2 P2) |
|
{ |
|
return ((P1.x - P0.x) * (P2.y - P0.y) |
|
- (P2.x - P0.x) * (P1.y - P0.y)); |
|
} |
|
}
|
|
|