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.
587 lines
22 KiB
587 lines
22 KiB
3 years ago
|
using UnityEngine;
|
||
|
using System.Collections;
|
||
|
using UnityEngine.UI;
|
||
|
using System;
|
||
|
using AX.TrackRecord;
|
||
|
using System.Text.RegularExpressions;
|
||
|
using System.Collections.Generic;
|
||
|
using UnityEngine.EventSystems;
|
||
|
using AX.MessageSystem;
|
||
|
|
||
|
public class FireDisasterSetting : MonoBehaviour
|
||
|
{
|
||
|
|
||
|
public Button SaveButton;
|
||
|
public string FireName;
|
||
|
private OtherArrribute_Fire fireAttri;
|
||
|
|
||
|
private InputField Comburent;//燃烧物
|
||
|
private InputField Position;//着火位置
|
||
|
private Toggle StraightSpread;//直线蔓延
|
||
|
private Toggle AreaSpread;//区域蔓延
|
||
|
private Toggle AroundSpread;//四周蔓延
|
||
|
private InputField StartTime;//开始蔓延时间
|
||
|
private Text TiShiText;//提示信息
|
||
|
|
||
|
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 GameObject lineObj;
|
||
|
private GameObject lineObjChild;
|
||
|
private GameObject linePrefab;
|
||
|
|
||
|
public Button CloseButton;
|
||
|
public Button ResetButton;
|
||
|
|
||
|
private Line line1 = new Line();//多边形最后一条边
|
||
|
private Line line2 = new Line();//多边形除最后一条边的其他各边
|
||
|
private Line line3 = new Line();//多边形倒数第二边
|
||
|
public GameObject messageBox;
|
||
|
|
||
|
// Use this for initialization
|
||
|
void Start()
|
||
|
{
|
||
|
SaveButton = this.transform.Find("SaveButton").GetComponent<Button>();
|
||
|
SaveButton.onClick.AddListener(SaveFireProperties);
|
||
|
|
||
|
CloseButton = this.transform.Find("CloseButton").GetComponent<Button>();
|
||
|
CloseButton.onClick.AddListener(CloseWindow);
|
||
|
|
||
|
ResetButton = this.transform.Find("ResetButton").GetComponent<Button>();
|
||
|
ResetButton.onClick.AddListener(ResetPath);
|
||
|
|
||
|
Comburent = this.transform.Find("ComburentInputField").GetComponent<InputField>();
|
||
|
Position = this.transform.Find("PosInputField").GetComponent<InputField>();
|
||
|
StraightSpread = this.transform.Find("Image").Find("Toggle").GetComponent<Toggle>();
|
||
|
AreaSpread = this.transform.Find("Image").Find("Toggle1").GetComponent<Toggle>();
|
||
|
AroundSpread = this.transform.Find("Image").Find("Toggle2").GetComponent<Toggle>();
|
||
|
StartTime = this.transform.Find("StartTimeInputField").GetComponent<InputField>();
|
||
|
TiShiText = this.transform.Find("TiShiText").GetComponent<Text>();
|
||
|
|
||
|
StraightSpread.onValueChanged.AddListener(CtrlStraightSpreadEdit);
|
||
|
AreaSpread.onValueChanged.AddListener(CtrlAreaSpreadEdit);
|
||
|
AroundSpread.onValueChanged.AddListener(CtrlAroundSpreadEdit);
|
||
|
|
||
|
linePrefab = Resources.Load<GameObject>("Prefabs/ToolPrefab/fireSpreadLine");
|
||
|
messageBox = GameObject.Find("Canvas").transform.Find("MessageBox").gameObject;
|
||
|
}
|
||
|
|
||
|
private void ResetPath()
|
||
|
{
|
||
|
PathPointList.Clear();
|
||
|
DeleteFireSpreadWay(GameObject.Find("pfirespreadline").transform.Find(FireName));
|
||
|
startPosition = GameObject.Find(FireName).transform.position;
|
||
|
|
||
|
//重置路径时,如果是已经蔓延过一次及存在蔓延出来的火,重置删除蔓延路径的同时,删除蔓延出来的火
|
||
|
Transform pfire = GameObject.Find("pfire").transform;
|
||
|
foreach (Transform child in pfire)
|
||
|
{
|
||
|
if (child.GetComponent<SpreadedFire>() && child.GetComponent<SpreadedFire>().fireSourceName == FireName)
|
||
|
{
|
||
|
Destroy(child.gameObject);
|
||
|
}
|
||
|
}
|
||
|
|
||
|
if (RecordManager.Instance.IsRecording)//记录火重置事件
|
||
|
{
|
||
|
MessageDispatcher.SendMessage("RecordResetFireEvent", (object)FireName);
|
||
|
}
|
||
|
}
|
||
|
|
||
|
private void CloseWindow()
|
||
|
{
|
||
|
this.gameObject.SetActive(false);
|
||
|
|
||
|
if (!GameObject.Find(FireName).GetComponent<ShowFireSetWin>().FireAttri.StraightSpread
|
||
|
&& !GameObject.Find(FireName).GetComponent<ShowFireSetWin>().FireAttri.AreaSpread
|
||
|
&& !GameObject.Find(FireName).GetComponent<ShowFireSetWin>().FireAttri.AroundSpread)
|
||
|
{
|
||
|
Destroy(GameObject.Find("pfirespreadline").transform.Find(FireName).gameObject);
|
||
|
}
|
||
|
else
|
||
|
{
|
||
|
if (GameObject.Find("pfirespreadline").transform.Find(FireName))
|
||
|
{
|
||
|
GameObject.Find("pfirespreadline").transform.Find(FireName).gameObject.SetActive(false);
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
|
||
|
private void SaveFireProperties()
|
||
|
{
|
||
|
if (StraightSpread.isOn || AreaSpread.isOn || AroundSpread.isOn)
|
||
|
{
|
||
|
if (string.IsNullOrEmpty(StartTime.text))
|
||
|
{
|
||
|
TiShiText.text = "开始时间不能为空";
|
||
|
return;
|
||
|
}
|
||
|
|
||
|
if (!string.IsNullOrEmpty(StartTime.text))
|
||
|
{
|
||
|
if (!Regex.Match(StartTime.text, "^[1-9]\\d*$").Success)
|
||
|
{
|
||
|
TiShiText.text = "开始时间应为大于0的整数";
|
||
|
return;
|
||
|
}
|
||
|
}
|
||
|
|
||
|
if (PathPointList.Count == 0)
|
||
|
{
|
||
|
TiShiText.text = "请设置蔓延路径或区域";
|
||
|
return;
|
||
|
}
|
||
|
|
||
|
if (AroundSpread.isOn)
|
||
|
{
|
||
|
List<Vector2> PathPointList_xz = new List<Vector2>();
|
||
|
for (int i = 0; i < PathPointList.Count; i++)
|
||
|
{
|
||
|
PathPointList_xz.Add(new Vector2(PathPointList[i].x,PathPointList[i].z));
|
||
|
}
|
||
|
|
||
|
Vector3 pos = GameObject.Find(FireName).transform.position;
|
||
|
Vector2 tempPos = new Vector2(pos.x,pos.z);
|
||
|
int wn = wn_PnPoly(PathPointList_xz, tempPos);
|
||
|
|
||
|
if (wn == 0)
|
||
|
{
|
||
|
TiShiText.text = "四周蔓延需包围火";
|
||
|
return;
|
||
|
}
|
||
|
}
|
||
|
|
||
|
if (FireName != null && FireName != "")
|
||
|
{
|
||
|
if (GameObject.Find(FireName).GetComponent<FireSpreadCtrl>().isSpreading)
|
||
|
{
|
||
|
TiShiText.text = "火已开始蔓延,不能保存";
|
||
|
return;
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
|
||
|
if (FireName != null && FireName != "")
|
||
|
{
|
||
|
fireAttri = GameObject.Find(FireName).GetComponent<ShowFireSetWin>().FireAttri;
|
||
|
|
||
|
fireAttri.Comburent = Comburent.text;
|
||
|
fireAttri.Position = Position.text;
|
||
|
|
||
|
fireAttri.StraightSpread = StraightSpread.isOn;
|
||
|
fireAttri.AreaSpread = AreaSpread.isOn;
|
||
|
fireAttri.AroundSpread = AroundSpread.isOn;
|
||
|
|
||
|
if (StraightSpread.isOn || AreaSpread.isOn || AroundSpread.isOn)
|
||
|
{
|
||
|
fireAttri.StartTime = int.Parse(StartTime.text);
|
||
|
|
||
|
fireAttri.PathPointList.Clear();
|
||
|
fireAttri.PathPointList.AddRange(PathPointList);
|
||
|
}
|
||
|
|
||
|
fireAttri.isSpreadedBeforeRecord = false;
|
||
|
|
||
|
fireAttri.isStartSpread = false;
|
||
|
|
||
|
if (RecordManager.Instance.IsRecording)
|
||
|
{
|
||
|
MessageDispatcher.SendMessage("RecordEditFireEvent", (object)FireName);
|
||
|
}
|
||
|
|
||
|
this.gameObject.SetActive(false);
|
||
|
if (GameObject.Find("pfirespreadline").transform.Find(FireName))
|
||
|
{
|
||
|
GameObject.Find("pfirespreadline").transform.Find(FireName).gameObject.SetActive(false);
|
||
|
}
|
||
|
|
||
|
//已经蔓延过一次,蔓延完成后,若再次设置并保存,需要重置此标识才能再次按F5启动蔓延
|
||
|
GameObject.Find(FireName).GetComponent<FireSpreadCtrl>().flag = false;
|
||
|
//GameObject.Find(FireName).GetComponent<FireSpreadCtrl>().spreadSpeed = 4.0f;
|
||
|
//GameObject.Find(FireName).GetComponent<FireSpreadCtrl>().repeatRate = 4.0f;
|
||
|
|
||
|
//设置过程中,保存后,也按设置的属性等待时间到后开始蔓延
|
||
|
MessageDispatcher.SendMessage(FireName, "SETFIRE", fireAttri);
|
||
|
}
|
||
|
}
|
||
|
|
||
|
private void CtrlStraightSpreadEdit(bool arg0)
|
||
|
{
|
||
|
if (arg0)
|
||
|
{
|
||
|
StartTime.interactable = true;
|
||
|
}
|
||
|
else
|
||
|
{
|
||
|
StartTime.interactable = false;
|
||
|
}
|
||
|
|
||
|
if (arg0 != GameObject.Find(FireName).GetComponent<ShowFireSetWin>().FireAttri.StraightSpread)
|
||
|
{
|
||
|
ResetPath();
|
||
|
}
|
||
|
}
|
||
|
|
||
|
private void CtrlAreaSpreadEdit(bool arg0)
|
||
|
{
|
||
|
if (arg0)
|
||
|
{
|
||
|
StartTime.interactable = true;
|
||
|
}
|
||
|
else
|
||
|
{
|
||
|
StartTime.interactable = false;
|
||
|
}
|
||
|
|
||
|
if (arg0 != GameObject.Find(FireName).GetComponent<ShowFireSetWin>().FireAttri.AreaSpread)
|
||
|
{
|
||
|
ResetPath();
|
||
|
}
|
||
|
}
|
||
|
|
||
|
private void CtrlAroundSpreadEdit(bool arg0)
|
||
|
{
|
||
|
if (arg0)
|
||
|
{
|
||
|
StartTime.interactable = true;
|
||
|
}
|
||
|
else
|
||
|
{
|
||
|
StartTime.interactable = false;
|
||
|
}
|
||
|
|
||
|
if (arg0 != GameObject.Find(FireName).GetComponent<ShowFireSetWin>().FireAttri.AroundSpread)
|
||
|
{
|
||
|
ResetPath();
|
||
|
}
|
||
|
}
|
||
|
|
||
|
// Update is called once per frame
|
||
|
void Update()
|
||
|
{
|
||
|
if (this.gameObject.activeSelf)
|
||
|
{
|
||
|
if (StraightSpread.isOn || AreaSpread.isOn || AroundSpread.isOn)
|
||
|
{
|
||
|
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("dimian")
|
||
|
|| hit.transform.gameObject.layer == LayerMask.NameToLayer("shineiFloor"))
|
||
|
{
|
||
|
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;
|
||
|
lineObjChild = Instantiate(linePrefab, tempPos, Quaternion.identity) as GameObject;
|
||
|
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,"提示信息","不能形成多边形");
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
|
||
|
private void DeleteFireSpreadWay(Transform fireSpreadWay)
|
||
|
{
|
||
|
foreach (Transform child in fireSpreadWay)
|
||
|
{
|
||
|
Destroy(child.gameObject);
|
||
|
}
|
||
|
}
|
||
|
|
||
|
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));
|
||
|
}
|
||
|
}
|