using System.Collections; using System.Collections.Generic; using UnityEngine; using LineUI; using UnityEngine.UI; using System.Linq; using ZIM; using o0; using Color = UnityEngine.Color; using InfraredManager; using Org.BouncyCastle.Asn1.Crmf; using ZIM.Unity; using o0.Project; using UnityEngine.SceneManagement; using o0InfraredLocate.ZIM; public enum ScreenPositioningStep { None, // Start,//开始界面 AutoEnd,//自动定位结束后界面 Marker,//进行标记界面 Manual,//手动界面 LightCtrl,//灯光调整界面 Successful,//结果选择界面 } public class LinePosition { public int index; public List pos; } public class InfraredScreenPositioningView : JCUnityLib.ViewBase { [SerializeField] RectTransform canvasRectTransform; [SerializeField] RectTransform draggableParent; [SerializeField] GameObject cameraLight; [SerializeField] RectTransform pointsParent; [SerializeField] RectTransform pos1; [SerializeField] RectTransform pos2; [SerializeField] RectTransform pos3; [SerializeField] RectTransform pos4; //画线时候的点偏移量 float offset = 10; [SerializeField] Line line; List oldLinePosition; Vector3 beginPos; Vector3 endPos; //相机感光部分 [SerializeField] Slider slider; [SerializeField] GameObject textTip1; [SerializeField] GameObject textTip2; [SerializeField] Button btnAuto; [SerializeField] Button btnHandMovement; [SerializeField] BtnRecordInfrared btnRecordInfrared; bool bAuto = true; [SerializeField] Color normalColor = Color.white; [SerializeField] Color highlightedColor = Color.green; [SerializeField] Color normalTextColor = Color.black; [SerializeField] Color highlightedTextColor = Color.white; [Header("Common Layout Group")] [SerializeField] GameObject mask; [SerializeField] Line maskLine; [SerializeField] RawImage rawImage; [Tooltip("Demo测试时候显示")] [SerializeField] RectTransform crosshair; [SerializeField] RectTransform crosshairRed; [Tooltip("存在校准数据时候显示")] [SerializeField] LineGenerator CurrentUILineGenerator;//开始显示屏幕线条 [Header("Start Layout Group")] [SerializeField] GameObject LayoutStart; [SerializeField] GameObject StartTextTip1; [SerializeField] GameObject StartTextTipHasData; [Tooltip("没有存在校准数据时候显示")] [SerializeField] GameObject BottomAutoBtn; [Tooltip("存在校准数据时候显示")] [SerializeField] GameObject BottomConfirmBtn; [Header("AutoEnd Layout Group")] [SerializeField] GameObject LayoutAutoEnd; [SerializeField] Button AutoEndConfirmBtn; [Tooltip("没有存在校准数据时候显示")] [SerializeField] GameObject TipAutoEnd; [Tooltip("存在校准数据时候显示")] [SerializeField] GameObject TipAutoEndHas; [Header("LightCtrl Layout Group")] [SerializeField] GameObject LayoutLightCtrl; [SerializeField] Slider sliderContrast; //亮度 [SerializeField] Slider sliderBrightness; [Tooltip("没有存在校准数据时候显示")] [SerializeField] GameObject TipLightCtrl; [SerializeField] Button LightCtrlManualButton; [Tooltip("存在校准数据时候显示")] [SerializeField] GameObject TipLightCtrlHas; [SerializeField] Button LightCtrlReturnButton; [Header("Marker Layout Group")] [SerializeField] GameObject LayoutMarker; [SerializeField] RectTransform crosshairSmall; [Tooltip("标记页面标题提示")] [SerializeField] TextAutoLanguage2 markerTextAutoLanguage2; [Tooltip("存在校准数据时候显示")] [SerializeField] GameObject TextTipMarker; [SerializeField] RectTransform markerPointsParent; [SerializeField] List markerPosList; [SerializeField] Line markerPointsLine; [SerializeField] PointMarker pointMarker; [Header("Manual Layout Group")] [SerializeField] GameObject LayoutManual; [Header("Successful Layout Group")] [SerializeField] GameObject LayoutSuccessful; [Tooltip("选择框的Line")] [SerializeField] Sprite[] ResultLines;// 0: 选中状态, 1: 未选中状态 [Tooltip("选择框图片")] [SerializeField] Image[] ResultImages; [Tooltip("选择框按钮")] [SerializeField] Button[] ResultImagesButtons; [SerializeField] Button[] ResultButtons; // 结果选择按钮 [SerializeField] RawImage CameraFirstImage; //第一个结果屏幕 [SerializeField] RawImage CameraSecondImage; //第二个结果屏幕 [SerializeField] LineGenerator FirstUILineGenerator;//第一个结果屏幕线条 [SerializeField] LineGenerator SecondUILineGenerator;//第二个结果屏幕线条 bool bMarkerFinish = false; ScreenPositioningStep perStepView = ScreenPositioningStep.None;//最后一次进入LayoutSuccessful的页面 //标记当前页面情况 ScreenPositioningStep curStepView = ScreenPositioningStep.Start;//设置一个开始页面 InfraredDemo infraredDemo; bool doLocateAuto; int DefaultResolutionIndex; private void Awake() { //设置一次显示相机的image 的颜色 rawImage.color = Color.white; offset = line.MyThickness; } void Start() { //获取InfraredDemo infraredDemo = InfraredDemo._ins; doLocateAuto = false; textTip1.SetActive(true); //设置btnAuto 高亮 //OnButtonClick(btnAuto); textTip2.SetActive(false); //动态设置marker的提示语 //if (BluetoothAim.ins!=null && markerTextAutoLanguage2 != null) //{ // string name = ""; // bool switchValue = false; // if (BluetoothAim.ins.isMainConnectToHOUYIPRO()) // { // name = TextAutoLanguage2.GetTextByKey("TitleTipMarker-HOUYIPro"); // } // else if (BluetoothAim.ins.isMainConnectToARTEMISPRO()) // { // name = TextAutoLanguage2.GetTextByKey("TitleTipMarker-ArtemisPro"); // } // else if (BluetoothAim.ins.isMainConnectToGun()) // { // //name = TextAutoLanguage2.GetTextByKey("TitleTipMarker-M9"); // switchValue = true; // } // if (switchValue) // { // markerTextAutoLanguage2.SetTextKey("TitleTipMarker-M9"); // } // else { // markerTextAutoLanguage2.textFormatArgs = new object[] { name }; // } //} if (markerTextAutoLanguage2 != null) { string name = TextAutoLanguage2.GetTextByKey("TitleTipMarker2-Common"); if (BluetoothAim.ins.isMainConnectToARTEMISPRO()) { name = TextAutoLanguage2.GetTextByKey("TitleTipMarker2-ArtemisPro"); } else if (BluetoothAim.ins.isMainConnectToGun()) { name = TextAutoLanguage2.GetTextByKey("TitleTipMarker2-Gun"); } markerTextAutoLanguage2.textFormatArgs = new object[] { name }; //markerTextAutoLanguage2.ApplyToText(); } //手动不高亮 //ResetButton(btnHandMovement); //quadUnityVectorList.Clear(); //quadUnityVectorList.Add(new Vector2(16.39f, 35.91f)); //quadUnityVectorList.Add(new Vector2(233.35f, 51.08f)); //quadUnityVectorList.Add(new Vector2(94.15f, 219.11f)); //quadUnityVectorList.Add(new Vector2(243.12f, 237.40f)); Debug.Log("quadUnityVectorList count:" + ScreenLocate.quadUnityVectorList.Count); if (ScreenLocate.quadUnityVectorList.Count == 0) { Debug.Log("GetLocalPos"); GetLocalPos(); } else { Vector2 texSize = ScreenLocate.Main.getUVCCameraInfoSize; Debug.Log("texSize:" + texSize + " = " + canvasRectTransform.rect); //自动识别时候四个点 SyncQuadUnityVectorListToPos(); //pos1.anchoredPosition = ScreenLocate.quadUnityVectorList[0].pixelToLocalPosition_AnchorCenter(Vector2.one, canvasRectTransform.rect); //pos2.anchoredPosition = ScreenLocate.quadUnityVectorList[1].pixelToLocalPosition_AnchorCenter(Vector2.one, canvasRectTransform.rect); //pos4.anchoredPosition = ScreenLocate.quadUnityVectorList[2].pixelToLocalPosition_AnchorCenter(Vector2.one, canvasRectTransform.rect); //pos3.anchoredPosition = ScreenLocate.quadUnityVectorList[3].pixelToLocalPosition_AnchorCenter(Vector2.one, canvasRectTransform.rect); } //更新start相关ui UpdateStartUI(); //记录操作的位置信息 oldLinePosition = new List(); SetLinePos(); //相机感光度 if (infraredDemo) { ////重置偏移量 //infraredDemo.ResetCenterOffset(); //////重置识别点 ////ScreenLocate.Main.ScreenIdentification.ClearQuadCache(); //////清除一下记录的点 ////ScreenLocate.quadUnityVectorList.Clear(); //infraredDemo.ResetPositioningData(); slider.onValueChanged.AddListener((value) => { infraredDemo.onSliderEvent(value); }); infraredDemo.onSetSliderValue(slider); //对比度 sliderContrast.onValueChanged.AddListener((value) => { infraredDemo.onSliderCustomEvent(value, -20.0f, 20.0f); }); infraredDemo.onSetSliderCustomValue(sliderContrast, -20.0f, 20.0f); //亮度 sliderBrightness.onValueChanged.AddListener((value) => { infraredDemo.onSliderCustomBrightnessEvent(value, -20.0f, 20.0f); }); infraredDemo.onSetSliderCustomBrightnessValue(sliderBrightness, -20.0f, 20.0f); offset = line.MyThickness = markerPointsLine.MyThickness = infraredDemo.lineWidth.Get(); //LineGenerator 比 line 宽少了大概2倍 CurrentUILineGenerator.LineThickness = infraredDemo.lineWidth.Get() * 2; //扇形宽 markerPointsLine.MyFanWidth = line.MyFanWidth = infraredDemo.fanWidth.Get(); QuadrilateralInCamera screen = ScreenLocate.Main.ScreenIdentification.Screen.QuadInCamera; CurrentUILineGenerator.Points = infraredDemo.ConvertQuadToPoints(screen, ScreenLocate.Main.getUVCCameraInfoSize); } else { //编辑器使用 if (Application.isEditor || Application.platform == RuntimePlatform.WindowsPlayer) { slider.onValueChanged.AddListener((value) => { double originalMin = 0.0; double originalMax = 10.0; double targetMin = -1; double targetMax = 1; // 计算转换后的值 double result = InfraredDemo.MapValue(value, originalMin, originalMax, targetMin, targetMax); //int _current = (int)(result); Debug.Log("_current:" + value + " , result:" + result); ScreenLocate.Main.pcContrast = (float)result; }); float v = ScreenLocate.Main.pcContrast; // 目标区间 [0, 10] 的边界值 double targetMin = 0.0; double targetMax = 10.0; double originalMin = -1; double originalMax = 1; // 计算转换后的值 double v2 = InfraredDemo.MapValue(v, originalMin, originalMax, targetMin, targetMax); Debug.Log("PC获取相机的感光度:" + v + " = " + v2); slider.SetValueWithoutNotify((float)v2); // 对 sliderContrast 和 sliderBrightness 调用统一的处理函数 HandleSliderValueChanged(sliderContrast, value => ScreenLocate.Main.pcContrast = value, ScreenLocate.Main.pcContrast); HandleSliderValueChanged(sliderBrightness, value => ScreenLocate.Main.pcBrightness = value, ScreenLocate.Main.pcBrightness); } } initSelectInfo(); //if (ScreenLocate.Main.getUVCTexture) //{ // //渲染相机画面 // rawImage.texture = ScreenLocate.Main.getUVCTexture; // //Debug.Log("rawImage.texture:" + rawImage.texture.name); //} //slider.onValueChanged.AddListener((value) => { // //onSliderEvent(value); // infraredDemo.SetBrightness(value); //}); //slider.value = infraredDemo.brightness.Get(); //修改分辨率。是否清晰一点? //DefaultResolutionIndex = infraredDemo?.ResolutionIndex ?? 0; //Debug.Log("[InfraredScreenPositioningView]开始记录进入时候的分辨率:" + DefaultResolutionIndex); //infraredDemo?.SetResolutionNew(ScreenLocate.Main.HighScreenLocateResolutionIndex); //if (SB_EventSystem.ins && SB_EventSystem.ins.simulateMouseIsAwaked) //{ // SB_EventSystem.ins.AwakenSimulateMouse(); // // Debug.Log("simulate-mouse-close"); //} } // 两个滑块值处理 void HandleSliderValueChanged(UnityEngine.UI.Slider slider, System.Action setValue, float pcValue) { double targetMin2 = -20.0; double targetMax2 = 20.0; double originalMin2 = -1; double originalMax2 = 1; slider.onValueChanged.AddListener((value) => { double result = InfraredDemo.MapValue(value, targetMin2, targetMax2, originalMin2, originalMax2); Debug.Log($"{slider.name}_current: {value}, result: {result}"); setValue((float)result); }); double mappedValue = InfraredDemo.MapValue(pcValue, originalMin2, originalMax2, targetMin2, targetMax2); Debug.Log($"{slider.name} PC获取相机的感光度: {pcValue} = {mappedValue}"); slider.SetValueWithoutNotify((float)mappedValue); } private void OnDestroy() { //修改回进入手动调节页面时候的分辨率 //infraredDemo?.SetResolutionNew(DefaultResolutionIndex); Debug.Log("OnDestroy*********************************AwakenSimulateMouse:" + SB_EventSystem.ins.simulateMouseIsAwaked); if (SB_EventSystem.ins && !SB_EventSystem.ins.simulateMouseIsAwaked) { SB_EventSystem.ins.AwakenSimulateMouse(); } } public RawImage Bg => rawImage; void Update() { if (enterFromZimWebCamera && ScreenLocate.Main.DebugOnZIMDemo) { // ZimWebCamera场景测试 rawImage.texture = ScreenLocate.Main.outputRawImages[7].texture; if (ScreenLocate.Main.infraredSpotBuffer[0].CameraLocation.HasValue) { // 检测到光点 var posInCanvas = ScreenLocate.Main.infraredSpotBuffer[0].CameraLocation.Value.pixelToLocalPosition_AnchorCenter(ScreenLocate.Main.CameraSize, rawImage.rectTransform.rect); crosshair.gameObject.SetActive(true); crosshair.anchoredPosition = posInCanvas; } else crosshair.gameObject.SetActive(false); //渲染相机画面 CameraSecondImage.texture = rawImage.texture; CameraFirstImage.texture = rawImage.texture; } else if (InfraredDemo.running) { //渲染相机画面 Texture texture = InfraredDemo.infraredCameraHelper.GetCameraTexture(); if (rawImage.texture == null || texture.GetNativeTexturePtr() != rawImage.texture.GetNativeTexturePtr()) { rawImage.texture = texture; //渲染相机画面 CameraSecondImage.texture = rawImage.texture; CameraFirstImage.texture = rawImage.texture; } if (ScreenLocate.Main.infraredSpotBuffer[0].CameraLocation.HasValue) { // 检测到光点 var posInCanvas = ScreenLocate.Main.infraredSpotBuffer[0].CameraLocation.Value.pixelToLocalPosition_AnchorCenter(ScreenLocate.Main.CameraSize, rawImage.rectTransform.rect); crosshairSmall.gameObject.SetActive(true); crosshairSmall.anchoredPosition = posInCanvas; } else crosshairSmall.gameObject.SetActive(false); //rawImage.material = InfraredDemo.infraredCameraHelper.GetCameraMaterial(); //可见光调节页面出现红十字光标 if (curStepView == ScreenPositioningStep.LightCtrl) { if (ScreenLocate.Main.infraredSpotBuffer[0].CameraLocation.HasValue) { // 检测到光点 var posInCanvas = ScreenLocate.Main.infraredSpotBuffer[0].CameraLocation.Value.pixelToLocalPosition_AnchorCenter(ScreenLocate.Main.CameraSize, rawImage.rectTransform.rect); crosshairRed.gameObject.SetActive(true); crosshairRed.anchoredPosition = posInCanvas; } else crosshairRed.gameObject.SetActive(false); } else if (crosshairRed.gameObject.activeSelf) { crosshairRed.gameObject.SetActive(false); } } } /// /// 根据enum操作ui /// /// public void SetScreenPositioningStepState(ScreenPositioningStep step = ScreenPositioningStep.None) { curStepView = step; AllScreenPositioningStepFalse(); QuadrilateralInCamera screenAuto = ScreenLocate.Main.ScreenIdentification.QuadAuto; switch (step) { case ScreenPositioningStep.Start: maskLine.SetDrawMask(true); LayoutStart.SetActive(true); UpdateStartUI(); break; case ScreenPositioningStep.AutoEnd: maskLine.SetDrawMask(true); LayoutAutoEnd.SetActive(true); pointsParent.gameObject.SetActive(false); CurrentUILineGenerator.enabled = true; if (screenAuto == null) { //不存在数据,走流程2 AutoEndConfirmBtn.interactable = false; TipAutoEndHas.SetActive(false); TipAutoEnd.SetActive(true); } else { //存在数据,显示确认按钮 AutoEndConfirmBtn.interactable = true; TipAutoEndHas.SetActive(true); TipAutoEnd.SetActive(false); } break; case ScreenPositioningStep.LightCtrl: maskLine.SetDrawMask(false); LayoutLightCtrl.SetActive(true); CurrentUILineGenerator.enabled = true; pointsParent.gameObject.SetActive(false); //setPointsLocation(ScreenLocate.quadUnityVectorList, pointsParent.gameObject, true); if (screenAuto == null) { //不存在数据,走流程2 TipLightCtrlHas.SetActive(false); TipLightCtrl.SetActive(true); LightCtrlReturnButton.gameObject.SetActive(false); LightCtrlManualButton.gameObject.SetActive(true); } else { //存在数据 TipLightCtrlHas.SetActive(true); TipLightCtrl.SetActive(false); LightCtrlReturnButton.gameObject.SetActive(true); LightCtrlManualButton.gameObject.SetActive(false); } break; case ScreenPositioningStep.Marker: //显示提示 pointMarker.ShowHintImageParent(true); perStepView = ScreenPositioningStep.Marker; bMarkerFinish = false; maskLine.SetDrawMask(true); LayoutMarker.SetActive(true); CurrentUILineGenerator.enabled = false; pointsParent.gameObject.SetActive(false); //setPointsLocation(ScreenLocate.quadUnityVectorList, pointsParent.gameObject, true); SyncQuadUnityVectorListToMarkerPointesPos(); TextTipMarker.SetActive(true); if (screenAuto == null) { ResetMarkerPointesPos(); } break; case ScreenPositioningStep.Manual: maskLine.SetDrawMask(true); SaveStartOldLinePosition(); perStepView = ScreenPositioningStep.Manual; bMarkerFinish = false; LayoutManual.SetActive(true); bAuto = false; doLocateAuto = false; draggableParent.gameObject.SetActive(true); pointsParent.gameObject.SetActive(false); if (screenAuto == null) { //不存在数据 onResetByMaskLine(); } break; case ScreenPositioningStep.Successful: LayoutSuccessful.SetActive(true); pointsParent.gameObject.SetActive(false); CurrentUILineGenerator.enabled = false; break; } } void AllScreenPositioningStepFalse() { LayoutStart.SetActive(false); LayoutMarker.SetActive(false); LayoutManual.SetActive(false); LayoutAutoEnd.SetActive(false); LayoutLightCtrl.SetActive(false); LayoutSuccessful.SetActive(false); onClearSuccessfullLineGenerator(); } /// /// 开始页面时候ui /// void UpdateStartUI() { pointsParent.gameObject.SetActive(false); CurrentUILineGenerator.enabled = true; if (ScreenLocate.quadUnityVectorList.Count == 0) { BottomConfirmBtn.SetActive(false); StartTextTip1.SetActive(true); StartTextTipHasData.SetActive(false); } else { //存在数据,显示确认按钮,确认按钮直接跳转到游戏 BottomConfirmBtn.SetActive(true); StartTextTip1.SetActive(false); StartTextTipHasData.SetActive(true); } } public void OnClick_Back() { AudioMgr.ins.PlayBtn(); ViewMgr.Instance.DestroyView(); } /// /// 返回最开始页面 /// public void OnClick_BackLayoutStart() { ClearPointsData(); SetScreenPositioningStepState(ScreenPositioningStep.Start); } void ClearPointsData() { //重置中心点0 infraredDemo.ResetCenterOffset(); //清除白线数据 infraredDemo.ResetPositioningData(); //上面应该清空了 ScreenLocate.Main.ScreenIdentification.QuadAuto onClearCurrentUILineGenerator(); } /// /// 进入环境光测试 /// public void OnClick_EnterLightCtrl() { SetScreenPositioningStepState(ScreenPositioningStep.LightCtrl); } /// /// 进入屏幕标记 /// public void OnClick_EnterMarker() { SetScreenPositioningStepState(ScreenPositioningStep.Marker); } /// /// successful 返回页面时候,根据ScreenPositioningStep区分 /// public void OnClick_BackByScreenPositioningStep() { SetScreenPositioningStepState(ScreenPositioningStep.LightCtrl); //清空两个绘制线 onClearSuccessfullLineGenerator(); //if(perStepView == ScreenPositioningStep.Manual) // SetScreenPositioningStepState(ScreenPositioningStep.Manual); //else // SetScreenPositioningStepState(ScreenPositioningStep.Marker); } /// /// 直接进入游戏流程 /// public void OnClick_EnterGame() { //对比确认效果。直接进入游戏引导页面 EnterGame(); } /// /// 进入自动流程校准操作 /// public void OnClick_EnterAuto() { Debug.Log("*********** OnClick_EnterAuto ************"); //自动按钮时候进入之前的校准流程 ClearPointsData(); OnClick_Auto(); } /// /// 进入标记页面自动流程校准操作 /// public void OnClick_EnterAutoByMarker() { Debug.Log("*********** OnClick_EnterAutoByMarker ************"); //自动按钮时候进入之前的校准流程 ClearPointsData(); markerPointsLine.SetLine(new List()); //隐藏提示 pointMarker.ShowHintImageParent(false); OnClick_Auto(); } /// /// 自动识别 /// public void OnClick_Auto() { bAuto = true; doLocateAuto = true; //textTip1.SetActive(false); //textTip2.SetActive(true); //ResetButton(btnAuto); if (enterFromZimWebCamera) { ScreenLocate _screenLocate = FindAnyObjectByType(); _screenLocate.EnterScreenLocateManualAuto(); return; } if (InfraredDemo.running) { InfraredDemo.infraredCameraHelper.EnterScreenLocateManualAuto(); } } /// /// 进入手动界面 /// public void OnClick_EnterManual() { SetScreenPositioningStepState(ScreenPositioningStep.Manual); } /// /// 切换成手动方式 /// public void onHandMovement() { bAuto = false; doLocateAuto = false; draggableParent.gameObject.SetActive(true); pointsParent.gameObject.SetActive(false); mask.SetActive(false); cameraLight.SetActive(true); } /// /// 自动识别后同步 /// public void SyncScreenPosition() { Vector2 texSize = ScreenLocate.Main.getUVCCameraInfoSize; Debug.Log("texSize:" + texSize + " = " + canvasRectTransform.rect); SyncQuadUnityVectorListToPos(); SetRectanglePoints(linePosConversion(pos1.localPosition, pos2.localPosition, pos3.localPosition, pos4.localPosition)); SyncQuadUnityVectorListToMarkerPointesPos(); //显示提示 pointMarker.ShowHintImageParent(true); AutoEndConfirmBtn.interactable = true; if (curStepView == ScreenPositioningStep.Start || curStepView == ScreenPositioningStep.AutoEnd) { //如果是开始页面进行自动定位的 if (curStepView != ScreenPositioningStep.AutoEnd) { SetScreenPositioningStepState(ScreenPositioningStep.AutoEnd); } } else if (curStepView == ScreenPositioningStep.Marker || curStepView == ScreenPositioningStep.Manual) { //显示最后结果 if(bMarkerFinish) SetScreenPositioningStepState(ScreenPositioningStep.Successful); } //屏幕变化情况下。同步修改对应的line //设置两个线段 QuadrilateralInCamera screenAuto = ScreenLocate.Main.ScreenIdentification.QuadAuto; QuadrilateralInCamera screenSemiAuto = ScreenLocate.Main.ScreenIdentification.QuadSemiAuto; if (screenAuto != null) { Debug.Log("[校准流程]Successful自动识别screenAuto信息 ------------ "); CurrentUILineGenerator.Points = infraredDemo.ConvertQuadToPoints(screenAuto, texSize); FirstUILineGenerator.Points = infraredDemo.ConvertQuadToPoints(screenAuto, texSize); } else { Debug.LogError("screenAuto 不存在!"); } if (screenSemiAuto != null) { Debug.Log("[校准流程]Successful半自动识别screenSemiAuto信息 ------------ "); SecondUILineGenerator.Points = infraredDemo.ConvertQuadToPoints(screenSemiAuto, texSize); } else { Debug.LogError("screenSemiAuto 不存在!"); } } /// /// 清空白线数据 /// void onClearCurrentUILineGenerator() { if (CurrentUILineGenerator.Points.Length != 0) CurrentUILineGenerator.Points = new Vector2[0];//System.Array.Clear(CurrentUILineGenerator.Points, 0, CurrentUILineGenerator.Points.Length); } /// /// 清空最后识别的两个自动和半自动数据线 /// void onClearSuccessfullLineGenerator() { if(FirstUILineGenerator.Points.Length !=0) FirstUILineGenerator.Points = new Vector2[0]; //System.Array.Clear(FirstUILineGenerator.Points, 0, FirstUILineGenerator.Points.Length); if (SecondUILineGenerator.Points.Length !=0) SecondUILineGenerator.Points = new Vector2[0]; //System.Array.Clear(SecondUILineGenerator.Points, 0, SecondUILineGenerator.Points.Length); } #region 绘制线段部分 //点击拖拽的开始位置 public void onBeginPos(int index, Vector3 pos) { Debug.Log("pos begin: " + pos); beginPos = pos; } public void onDragPos(int index, Vector3 pos) { //设置线段的点 SetRectanglePoints(linePosConversion(pos1.localPosition, pos2.localPosition, pos3.localPosition, pos4.localPosition)); } //点击拖拽的结束位置 public void onEndPos(int index, Vector3 pos) { Debug.Log("pos end: " + pos); endPos = pos; if (beginPos == endPos) return; //Debug.Log(index+",最后的点:" + pos); //再记录一次最后的点 SetLinePos(); } //同步设置图片对应的位置到line public void SetLinePos() { //记录一个操作点的操作位置 AddOldLinePosition(); //设置线段的点 SetRectanglePoints(linePosConversion(pos1.localPosition, pos2.localPosition, pos3.localPosition, pos4.localPosition)); } void AddOldLinePosition() { Vector3[] v = new Vector3[4]; pos1.GetWorldCorners(v); Vector3[] v1 = new Vector3[4]; pos1.GetLocalCorners(v1); //for (int i = 0; i < 4; i++) //{ // Debug.Log(i + " =1= " + v[i]); // Debug.Log(i + " =2= " + v1[i]); //} //记录一个操作点的操作位置 List screenPositions = new List(); screenPositions.Add(pos1.localPosition); screenPositions.Add(pos2.localPosition); screenPositions.Add(pos3.localPosition); screenPositions.Add(pos4.localPosition); LinePosition linePosition = new LinePosition(); linePosition.index = oldLinePosition.Count; linePosition.pos = screenPositions; oldLinePosition.Add(linePosition); } /// /// 记录一个开始位置 /// void SaveStartOldLinePosition() { oldLinePosition.Clear(); //记录一个操作点的操作位置 List screenPositions = new List(); screenPositions.Add(pos1.localPosition); screenPositions.Add(pos2.localPosition); screenPositions.Add(pos3.localPosition); screenPositions.Add(pos4.localPosition); LinePosition linePosition = new LinePosition(); linePosition.index = 1; linePosition.pos = screenPositions; oldLinePosition.Add(linePosition); } //转换绘制线段的点 List linePosConversion(Vector3 _pos1, Vector3 _pos2, Vector3 _pos3, Vector3 _pos4) { List _screenPositions = new List(); //点为负数的增大 offset,正数减少 offset //Vector2 startPos1 = new Vector2(_pos1.x - pos1.rect.width * 0.5f + offset, _pos1.y - pos1.rect.height * 0.5f + offset); //Vector2 startPos2 = new Vector2(_pos2.x + pos2.rect.width * 0.5f - offset, _pos2.y - pos2.rect.height * 0.5f + offset); //Vector2 startPos3 = new Vector2(_pos3.x + pos3.rect.width * 0.5f - offset, _pos3.y + pos3.rect.height * 0.5f - offset); //Vector2 startPos4 = new Vector2(_pos4.x - pos4.rect.width * 0.5f + offset, _pos4.y + pos4.rect.height * 0.5f - offset); Vector2 startPos1 = new Vector2(_pos1.x + offset, _pos1.y + offset); Vector2 startPos2 = new Vector2(_pos2.x - offset, _pos2.y + offset); Vector2 startPos3 = new Vector2(_pos3.x - offset, _pos3.y - offset); Vector2 startPos4 = new Vector2(_pos4.x + offset, _pos4.y - offset); _screenPositions.Add(startPos1); _screenPositions.Add(startPos2); _screenPositions.Add(startPos3); _screenPositions.Add(startPos4); return _screenPositions; } void SetRectanglePoints(List screenPositions) { line.SetLine(screenPositions); } //撤回上一个元素 public void onRecall() { // 获取并删除最后一个元素,并且保留一个元素 if (oldLinePosition.Count > 1) // 确保列表不为空 { // 获取回退的那个元素点 LinePosition lastElement_second = oldLinePosition[oldLinePosition.Count - 2]; // 获取最后一个元素 //LinePosition lastElement = oldLinePosition[oldLinePosition.Count - 1]; //Debug.Log(JsonUtility.ToJson(lastElement) + " = " + oldLinePosition.Count); oldLinePosition.RemoveAt(oldLinePosition.Count - 1); // 删除最后一个元素 pos1.localPosition = lastElement_second.pos[0]; pos2.localPosition = lastElement_second.pos[1]; pos3.localPosition = lastElement_second.pos[2]; pos4.localPosition = lastElement_second.pos[3]; //设置线段的点 SetRectanglePoints(linePosConversion(lastElement_second.pos[0], lastElement_second.pos[1], lastElement_second.pos[2], lastElement_second.pos[3])); } } //是不是从Demo界面进入该页面的 public bool enterFromInfraredDemo { get; set; } = false; //是否从测试场景进入 public bool enterFromZimWebCamera { get; set; } = false; //确认修改 public void onConfirmation() { if (enterFromZimWebCamera) { ConfirmScreenLocateManualTest(); if (oldLinePosition.Count > 1) // 确保列表不为空 { LinePosition lastElement = oldLinePosition[oldLinePosition.Count - 1]; oldLinePosition.Clear(); oldLinePosition.Add(lastElement); } SaveLocalPos(); AudioMgr.ins.PlayBtn(); ViewManager2.HideView(ViewManager2.Path_InfraredScreenPositioningView); return; } if (!ConfirmScreenLocateManual()) return; if (oldLinePosition.Count > 1) // 确保列表不为空 { //LinePosition lastElement = oldLinePosition[oldLinePosition.Count - 1]; oldLinePosition.Clear(); //oldLinePosition.Add(lastElement); } if (InfraredDemo.running) { //跳转入界面 AudioMgr.ins.PlayBtn(); if (!enterFromInfraredDemo) { //每次初始化重置一下引导 infraredDemo.resetInfraredPlayerPrefs(); //GameObject connectGuidanceView = ViewManager2.getGameObjectAndShowView(ViewManager2.Path_ConnectGuidanceView); //connectGuidanceView.GetComponent().showTextipInfrared(); if (!PlayerPrefs.HasKey("hideInfraredBowAndArrow")) { //如果是红外连接成功,记录一个tag PlayerPrefs.SetInt("hideInfraredBowAndArrow", 1); } onEnterInfrared(); } else { ViewManager2.HideView(ViewManager2.Path_InfraredScreenPositioningView); } } //存储一次节点 SaveLocalPos(); } //重置位置 public void onReset() { oldLinePosition.Clear(); // 获取屏幕的四个角的像素坐标 Vector2 bottomLeft = new Vector2(0, 0); // 将屏幕像素坐标转换为 Canvas 的局部坐标 Vector2 localBottomLeft; RectTransformUtility.ScreenPointToLocalPointInRectangle(canvasRectTransform, bottomLeft, null, out localBottomLeft); // 打印结果 Debug.Log("Local Bottom Left: " + localBottomLeft); //int _x = Mathf.FloorToInt(Mathf.Abs(localBottomLeft.x) - 120), _y = Mathf.FloorToInt(Mathf.Abs(localBottomLeft.y) - 77); int _x = Mathf.FloorToInt(Mathf.Abs(localBottomLeft.x)), _y = Mathf.FloorToInt(Mathf.Abs(localBottomLeft.y)); pos1.anchoredPosition = new Vector3(-_x, -_y, 0); //Bottom Left pos2.anchoredPosition = new Vector3(_x, -_y, 0); //Bottom Right pos3.anchoredPosition = new Vector3(_x, _y, 0); //Top Right pos4.anchoredPosition = new Vector3(-_x, _y, 0); //Top Left //pos1.anchoredPosition = new Vector3(_x, _y, 0); //pos2.anchoredPosition = new Vector3(-_x, _y, 0); //pos3.anchoredPosition = new Vector3(-_x, -_y, 0); //pos4.anchoredPosition = new Vector3(_x, -_y, 0); //设置一次位置 SetLinePos(); btnRecordInfrared.Reset(); ScreenLocate.Main.ScreenIdentification.ClearQuadCache(); if (enterFromZimWebCamera) { ScreenLocate.Main.ScreenQuad.gameObject.SetActive(false); ScreenLocate.Main.UILineGenerator.Points = new Vector2[0]; } if (curStepView == ScreenPositioningStep.Start || curStepView == ScreenPositioningStep.AutoEnd) { //如果是开始页面进行自动定位的失败的 if (curStepView != ScreenPositioningStep.AutoEnd) { SetScreenPositioningStepState(ScreenPositioningStep.AutoEnd); } AutoEndConfirmBtn.interactable = false; } } /// /// 根据MaskLine 重置 可拖拽的 line 部分数据 /// public void onResetByMaskLine() { oldLinePosition.Clear(); List _markLine = maskLine.ScreenPositions; pos1.anchoredPosition = _markLine[0];//Bottom Left pos2.anchoredPosition = _markLine[1]; //Bottom Right pos3.anchoredPosition = _markLine[2]; //Top Right pos4.anchoredPosition = _markLine[3];//Top Left //设置一次位置 SetLinePos(); } /// /// 标准四个点 /// /// /// public void onManualNewPos(int index, Vector3 pos) { Debug.Log("pos end: " + pos); if (index == 0) pos1.localPosition = pos; else if (index == 1) pos2.localPosition = pos; else if (index == 2) pos3.localPosition = pos; else if (index == 3) pos4.localPosition = pos; //再记录一次最后的点 SetLinePos(); } /// /// 处理新流程,先记录手动,然后到自动识别处理 /// public void onManualToAutomatic() { if (enterFromZimWebCamera) { ConfirmScreenLocateManualTest(); if (oldLinePosition.Count > 1) // 确保列表不为空 { LinePosition lastElement = oldLinePosition[oldLinePosition.Count - 1]; oldLinePosition.Clear(); oldLinePosition.Add(lastElement); } SaveLocalPos(); //到自动 OnClick_Auto(); return; } if (!ConfirmScreenLocateManual()) { Debug.LogError("ConfirmScreenLocateManual is false!"); return; } if (oldLinePosition.Count > 1) // 确保列表不为空 { LinePosition lastElement = oldLinePosition[oldLinePosition.Count - 1]; oldLinePosition.Clear(); oldLinePosition.Add(lastElement); } //存储一次节点 SaveLocalPos(); Debug.Log("[校准流程]进入自动校准数据,调用EnterScreenLocateManualAuto"); bAuto = true; doLocateAuto = true; //自动校准 InfraredDemo.infraredCameraHelper.EnterScreenLocateManualAuto(); } /// /// PointMarker 调用 /// public void onFinishManualToAutomatic() { bMarkerFinish = true; onManualToAutomatic(); } #endregion List _locatePointList = new(); float _texWidth; float _texHeight; void RecordLocatePoint(RectTransform p, Vector2 pivot) { Vector2 pos = JCUnityLib.RectTransformUtils.GetPositionByPivot(p, pivot); pos.x = Mathf.Clamp01(pos.x / Screen.width); pos.y = Mathf.Clamp01(pos.y / Screen.height); _locatePointList.Add(pos); } bool ConfirmScreenLocateManual() { if (InfraredDemo.running) { //渲染截图 Texture2D texture2D = InfraredDemo.infraredCameraHelper.EnterScreenLocateManual(); if (texture2D == null) { Debug.Log("EnterScreenLocateManual = null"); InfraredDemo.infraredCameraHelper.QuitScreenLocateManual(null); return false; } _locatePointList.Clear(); _texWidth = texture2D.width; _texHeight = texture2D.height; RecordLocatePoint(pos1, new Vector2(0, 0)); RecordLocatePoint(pos2, new Vector2(1, 0)); RecordLocatePoint(pos3, new Vector2(1, 1)); RecordLocatePoint(pos4, new Vector2(0, 1)); //RecordLocatePoint(pos1, new Vector2(0.5f, 0.5f)); //RecordLocatePoint(pos2, new Vector2(0.5f, 0.5f)); //RecordLocatePoint(pos3, new Vector2(0.5f, 0.5f)); //RecordLocatePoint(pos4, new Vector2(0.5f, 0.5f)); InfraredDemo.infraredCameraHelper.QuitScreenLocateManual(_locatePointList); FindObjectOfType().SetLocatePointsToCameraRender(_locatePointList, 1, 1); //同步数据 ScreenLocate.quadUnityVectorList.Clear(); ScreenLocate.quadUnityVectorList.Add(_locatePointList[0]); ScreenLocate.quadUnityVectorList.Add(_locatePointList[1]); //两个点切换,顺序不一样 ScreenLocate.quadUnityVectorList.Add(_locatePointList[3]); ScreenLocate.quadUnityVectorList.Add(_locatePointList[2]); ScreenLocate.SaveScreenLocateVectorList(); Debug.Log("[校准流程]设置QuitScreenLocateManual()手动数据,保存quadUnityVectorList"); return true; } return false; } void ConfirmScreenLocateManualTest() { //渲染截图 ScreenLocate _screenLocate = FindAnyObjectByType(); Texture2D texture2D = _screenLocate.EnterScreenLocateManual(); if (texture2D == null) { _screenLocate.QuitScreenLocateManual(null); return; } _locatePointList.Clear(); _texWidth = texture2D.width; _texHeight = texture2D.height; RecordLocatePoint(pos1, new Vector2(0, 0)); RecordLocatePoint(pos2, new Vector2(1, 0)); RecordLocatePoint(pos3, new Vector2(1, 1)); RecordLocatePoint(pos4, new Vector2(0, 1)); _screenLocate.QuitScreenLocateManual(_locatePointList); //FindObjectOfType().SetLocatePointsToCameraRender(_locatePointList, _texWidth, _texHeight); setPointsLocation(_locatePointList,pointsParent.gameObject,!bAuto); if (!doLocateAuto) // 设置手动定位数据 setPointsManual(_locatePointList, GameObject.Find("WebCameraView/CameraImage0/ScreenQuad")); //同步数据 ScreenLocate.quadUnityVectorList.Clear(); ScreenLocate.quadUnityVectorList.Add(new Vector2(_locatePointList[0].x, _locatePointList[0].y)); ScreenLocate.quadUnityVectorList.Add(new Vector2(_locatePointList[1].x, _locatePointList[1].y)); //两个点切换,顺序不一样 ScreenLocate.quadUnityVectorList.Add(new Vector2(_locatePointList[3].x, _locatePointList[3].y)); ScreenLocate.quadUnityVectorList.Add(new Vector2(_locatePointList[2].x, _locatePointList[2].y)); ScreenLocate.SaveScreenLocateVectorList(); } void setPointsLocation(List targetList, GameObject pointsTF2, bool active = true) { //GameObject pointsTF2 = GameObject.Find("WebCameraView/CameraImage0/ScreenQuad"); pointsTF2.SetActive(active); if (pointsTF2.transform.childCount == targetList.Count) { for (int i = 0; i < pointsTF2.transform.childCount; i++) { Transform pointTF = pointsTF2.transform.GetChild(i); Vector2 pos = targetList[i]; pointTF.localPosition = pos.pixelToLocalPosition_AnchorCenter(Vector2.one, pointsTF2.GetComponent().rect); pointTF.gameObject.SetActive(true); } } } void setPointsManual(List targetList, GameObject pointsTF2, bool active = true) { setPointsLocation(targetList, pointsTF2, active); var lo = new Vector2(-0.5f, -0.5f); ScreenLocate.Main.UILineGenerator.Points = new Vector2[4] { 2 * (targetList[0] + lo), 2 * (targetList[1] + lo), 2 * (targetList[2] + lo), 2 * (targetList[3] + lo) }; } void SaveLocalPos() { List screenPositions = new List(); screenPositions.Add(pos1.anchoredPosition); screenPositions.Add(pos2.anchoredPosition); screenPositions.Add(pos3.anchoredPosition); screenPositions.Add(pos4.anchoredPosition); string saveStr = string.Join(';', screenPositions.Select(v => $"{v.x},{v.y}")); //,{v.z} Debug.Log("Local UI Position: " + saveStr); PlayerPrefs.SetString("ScreenPositioningView", saveStr); } void GetLocalPos() { string posListStr = PlayerPrefs.GetString("ScreenPositioningView", ""); if (!string.IsNullOrWhiteSpace(posListStr)) { List posList = posListStr.Split(';') .Select(s => { string[] parts = s.Split(','); return new Vector2(float.Parse(parts[0]), float.Parse(parts[1])); }) .ToList(); pos1.anchoredPosition = posList[0]; pos2.anchoredPosition = posList[1]; pos3.anchoredPosition = posList[2]; pos4.anchoredPosition = posList[3]; SetRectanglePoints(linePosConversion(pos1.localPosition, pos2.localPosition, pos3.localPosition, pos4.localPosition)); } } #region 按钮颜色切换 private void OnButtonClick(Button button) { // 切换按钮颜色 ColorBlock colors = button.colors; colors.normalColor = highlightedColor; colors.highlightedColor = highlightedColor; button.colors = colors; // 切换字体颜色 Text buttonText = button.GetComponentInChildren(); buttonText.color = highlightedTextColor; } private void ResetButton(Button button) { // 重置按钮颜色 ColorBlock colors = button.colors; colors.normalColor = normalColor; colors.highlightedColor = normalColor; button.colors = colors; // 重置字体颜色 Text buttonText = button.GetComponentInChildren(); buttonText.color = normalTextColor; } #endregion #region 标定完成之后进入游戏界面 void onEnterInfrared() { //添加进入射箭场景 if (PlayerPrefs.GetInt("entry-guider-infrared-" + LoginMgr.myUserInfo.id, 0) == 0) { Debug.Log("-----进入射箭场景!"); NewUserGuiderManager newUserGuiderManager = FindObjectOfType(); newUserGuiderManager.curConfigKey = "开始-红外调整"; //b端都是红外设备流程 if (CommonConfig.StandaloneModeOrPlatformB) { newUserGuiderManager.isNewModule = true; } else { newUserGuiderManager.isNewModule = AimHandler.ins.aimDeviceInfo.type == (int)AimDeviceType.HOUYIPRO || AimHandler.ins.aimDeviceInfo.type == (int)AimDeviceType.Gun || AimHandler.ins.aimDeviceInfo.type == (int)AimDeviceType.ARTEMISPRO; } //进入射箭场景 GlobalData.pkMatchType = PKMatchType.None; GameMgr.gameType = 1; //射一箭回到连接页面,Device.view GameMgr.bNavBack = true; GameMgr.bShowDistance = false; if (!CommonConfig.StandaloneModeOrPlatformB) { AimHandler.ins.bInitOne = false;//true } //关闭计时器 GameMgr.turnOffTimer = true; //关闭左边靶子和底部速度栏 GameMgr.HideTargetView = true; GameMgr.HideBillboard = true; GameMgr.ButtonCount = 0; UnityEngine.SceneManagement.SceneManager.LoadScene( "Game", UnityEngine.SceneManagement.LoadSceneMode.Single); PlayerPrefs.SetInt("entry-guider-infrared-" + LoginMgr.myUserInfo.id, 1); } else { Debug.Log("-----跳转回连接界面!"); //如不是第一次,则应该跳转回连接界面 ViewMgr.Instance.DestroyView(); ViewManager2.HideView(ViewManager2.Path_ConnectGuidanceView); } } #endregion #region 最后选择算法处理UI int selected = -1; void initSelectInfo() { for (int i = 0; i < 2; i++) { int currentIndex = i; // 将 i 赋值给局部变量 ResultImagesButtons[currentIndex].onClick.AddListener(() => SelectImage(currentIndex)); //ResultButtons[currentIndex].onClick.AddListener(() => //{ // if (currentIndex == 0) // { // OnFirstResult(); // } // else if (currentIndex == 1) // { // OnSecondResult(); // } //}); } //默认选择1 自动 SelectImage(0); } // 添加一个选择函数 void SelectImage(int selectedIndex) { //如果重复选中则跳转 if (selected == selectedIndex) { if (selected == 0) { OnFirstResult(); } else if (selected == 1) { OnSecondResult(); } return; } // 遍历所有图片 selected = selectedIndex; //for (int i = 0; i < ResultImages.Length; i++) //{ // // 如果是选中的 index,赋值为 ResultLines[0],否则赋值为 ResultLines[1] // if (i == selectedIndex) // { // selected = i; // ResultImages[i].sprite = ResultLines[0]; // ResultButtons[i].interactable = true; // } // else // { // ResultImages[i].sprite = ResultLines[1]; // ResultButtons[i].interactable = false; // } //} } //选择全自动结果后进入游戏 void OnFirstResult() { ScreenLocate.Main.SelectScreenAfterLocate(ScreenLocate.ScreenIdentificationTag.Auto); UpdateQuadUnityVectorList(); onCompelete(); } //选择半自动结果 void OnSecondResult() { ScreenLocate.Main.SelectScreenAfterLocate(ScreenLocate.ScreenIdentificationTag.SemiAuto); UpdateQuadUnityVectorList(); onCompelete(); } public void onCompelete() { if (enterFromZimWebCamera) { SaveLocalPos(); ViewManager2.HideView(ViewManager2.Path_InfraredScreenPositioningView); return; } EnterGame(); //存储一次节点 SaveLocalPos(); } void EnterGame() { if (InfraredDemo.running) { //跳转入界面 AudioMgr.ins.PlayBtn(); if (!enterFromInfraredDemo) { //每次初始化重置一下引导 infraredDemo.resetInfraredPlayerPrefs(); //GameObject connectGuidanceView = ViewManager2.getGameObjectAndShowView(ViewManager2.Path_ConnectGuidanceView); //connectGuidanceView.GetComponent().showTextipInfrared(); if (!PlayerPrefs.HasKey("hideInfraredBowAndArrow")) { //如果是红外连接成功,记录一个tag PlayerPrefs.SetInt("hideInfraredBowAndArrow", 1); } onEnterInfrared(); } else { ViewManager2.HideView(ViewManager2.Path_InfraredScreenPositioningView); } } } /// /// 选择模式后更新 quadUnityVectorList /// void UpdateQuadUnityVectorList() { ScreenLocate.Main.UpdateQuadUnityVectorList(); SyncQuadUnityVectorListToPos(); infraredDemo?.SetLocatePointsToCameraRender(ScreenLocate.quadUnityVectorList, 1, 1); _locatePointList.Clear(); } void SyncQuadUnityVectorListToPos() { Debug.Log("[ScreenLocate] SyncQuadUnityVectorListToPos quadUnityVectorList:" + ScreenLocate.Main.PrintVector2List(ScreenLocate.quadUnityVectorList)); pos1.anchoredPosition = ScreenLocate.quadUnityVectorList[0].pixelToLocalPosition_AnchorCenter(Vector2.one, canvasRectTransform.rect); pos2.anchoredPosition = ScreenLocate.quadUnityVectorList[1].pixelToLocalPosition_AnchorCenter(Vector2.one, canvasRectTransform.rect); pos4.anchoredPosition = ScreenLocate.quadUnityVectorList[2].pixelToLocalPosition_AnchorCenter(Vector2.one, canvasRectTransform.rect); pos3.anchoredPosition = ScreenLocate.quadUnityVectorList[3].pixelToLocalPosition_AnchorCenter(Vector2.one, canvasRectTransform.rect); } //这个脚本存在时候。任何切换操作都直接处理删除 //void OnSceneUnloaded(Scene scene) //{ // ViewManager2.HideView(ViewManager2.Path_ConnectGuidanceView); // ViewManager2.HideView(ViewManager2.Path_InfraredScreenPositioningView); //} //void OnEnable() //{ // SceneManager.sceneUnloaded += OnSceneUnloaded; //} //void OnDisable() //{ // SceneManager.sceneUnloaded -= OnSceneUnloaded; //} #endregion #region 判断点是否在 quad 内部 //判断maskline public bool IsPointInMaskLine(Vector2 point) { return IsPointInQuad(point, maskLine.ScreenPositions); } //实现基于射线法,通过数交点的奇偶性来判断点是否在多边形内 bool IsPointInQuad(Vector2 point, List quadVertices) { if (quadVertices.Count != 4) { Debug.LogError("Quad must have exactly 4 vertices."); return false; } bool isInside = false; int vertexCount = quadVertices.Count; for (int i = 0, j = vertexCount - 1; i < vertexCount; j = i++) { Vector2 vi = quadVertices[i]; Vector2 vj = quadVertices[j]; // 检查射线是否与边相交 if (((vi.y > point.y) != (vj.y > point.y)) && (point.x < (vj.x - vi.x) * (point.y - vi.y) / (vj.y - vi.y) + vi.x)) { isInside = !isInside; } } return isInside; } /// /// 判断四个点是否能够形成有效的四边形,并根据面积阈值过滤小四边形 /// /// 四个点 /// 面积阈值,用于过滤面积太小的四边形 /// 是否是有效的四边形 public bool IsValidQuadrilateral(Vector2[] points, float minArea = 100000.0f) { if (points.Length != 4) { Debug.Log("四个点数不足,无法形成四边形。"); return false; // 如果点数不是4,直接返回false } // 计算四边形的面积 float area = CalculateArea(points); Debug.Log($"四边形面积: {area}"); if (area < minArea) { Debug.Log($"面积小于阈值: {minArea},返回 false。"); return false; // 面积太小,返回 false } // 检查是否有三点共线 for (int i = 0; i < points.Length; i++) { Vector2 a = points[i]; Vector2 b = points[(i + 1) % points.Length]; Vector2 c = points[(i + 2) % points.Length]; if (ArePointsCollinear(a, b, c)) { Debug.Log($"点 {a}, {b}, {c} 共线,返回 false。"); return false; // 存在共线点,返回 false } } // 检查是否为矩形或接近矩形 if (!IsRectangle(points)) { // 如果不是矩形,检查是否是梯形 if (!IsTrapezoid(points)) { Debug.Log("既不是矩形,也不是梯形,返回 false。"); return false; // 不是矩形也不是梯形,返回 false } else { Debug.Log("是梯形。"); } } else { Debug.Log("是矩形。"); } // 检查对角线是否相交 if (DoLinesIntersect(points[0], points[1], points[2], points[3]) || DoLinesIntersect(points[1], points[2], points[3], points[0])) { Debug.Log("对角线相交,返回 false。"); return false; // 对角线相交,返回 false } // 检查点的排列顺序,确保是顺时针或逆时针 if (!ArePointsClockwise(points) && !ArePointsClockwise(points.Reverse().ToArray())) { Debug.Log("点的排列顺序不正确,返回 false。"); return false; // 点的排列顺序不正确 } Debug.Log("四边形有效,返回 true。"); return true; // 通过所有检查,返回 true } /// /// 判断是否是矩形(近似90度角) /// private bool IsRectangle(Vector2[] points) { // 角度容差范围,允许夹角有小的偏差 const float dotProductThreshold = 0.1f; for (int i = 0; i < points.Length; i++) { Vector2 a = points[i]; Vector2 b = points[(i + 1) % points.Length]; Vector2 c = points[(i + 2) % points.Length]; // 计算向量 AB 和 BC 的内积 Vector2 ab = b - a; Vector2 bc = c - b; float dotProduct = Vector2.Dot(ab.normalized, bc.normalized); // 如果内积接近 0,表示夹角接近 90 度 if (Mathf.Abs(dotProduct) > dotProductThreshold) { Debug.Log($"点 {a}, {b}, {c} 的夹角不接近 90 度,返回 false。"); return false; // 角度不接近 90 度 } } return true; } /// /// 判断是否是梯形 /// private bool IsTrapezoid(Vector2[] points) { // 斜率容差范围,允许斜率差异较小 const float slopeThreshold = 0.2f; // 计算对角线的斜率 float slope1 = (points[1].y - points[0].y) / (points[1].x - points[0].x); float slope2 = (points[3].y - points[2].y) / (points[3].x - points[2].x); // 如果对角线斜率差异小于容差范围,则认为是梯形 if (Mathf.Abs(slope1 - slope2) < slopeThreshold) { Debug.Log("对角线平行,判断为梯形。"); return true; // 对角线平行,返回 true } else { Debug.Log($"对角线斜率差异过大: {slope1} vs {slope2},不是梯形,返回 false。"); return false; // 斜率差异过大,不是梯形 } } //计算四边形面积 float CalculateArea(Vector2[] points) { float area = 0f; int n = points.Length; for (int i = 0; i < n; i++) { Vector2 current = points[i]; Vector2 next = points[(i + 1) % n]; area += current.x * next.y - current.y * next.x; } return Mathf.Abs(area) / 2f; } //确保点不共线 //判断点是否在同一条直线上(即共线),如果共线则无法形成四边形。可以通过计算任意三点的面积是否为 0 来验证是否共线: bool ArePointsCollinear(Vector2 a, Vector2 b, Vector2 c) { float area = Mathf.Abs(a.x * (b.y - c.y) + b.x * (c.y - a.y) + c.x * (a.y - b.y)) / 2.0f; return Mathf.Approximately(area, 0f); } //确保边不相交 bool DoLinesIntersect(Vector2 a, Vector2 b, Vector2 c, Vector2 d) { float cross(Vector2 p1, Vector2 p2, Vector2 p3) { return (p2.x - p1.x) * (p3.y - p1.y) - (p2.y - p1.y) * (p3.x - p1.x); } float d1 = cross(a, b, c); float d2 = cross(a, b, d); float d3 = cross(c, d, a); float d4 = cross(c, d, b); return d1 * d2 < 0 && d3 * d4 < 0; } //顺时针或逆时针排列顶点 bool ArePointsClockwise(Vector2[] points) { float sum = 0; for (int i = 0; i < points.Length; i++) { Vector2 current = points[i]; Vector2 next = points[(i + 1) % points.Length]; sum += (next.x - current.x) * (next.y + current.y); } return sum < 0; // 小于0为顺时针,大于0为逆时针 } #endregion #region marker line 部分渲染 /// /// maker 界面渲染 /// void SyncQuadUnityVectorListToMarkerPointesPos() { if (ScreenLocate.quadUnityVectorList.Count == 4) { Debug.Log("[ScreenLocate] SyncQuadUnityVectorListToMarkerPointesPos quadUnityVectorList:" + ScreenLocate.Main.PrintVector2List(ScreenLocate.quadUnityVectorList)); markerPosList[0].anchoredPosition = ScreenLocate.quadUnityVectorList[0].pixelToLocalPosition_AnchorCenter(Vector2.one, canvasRectTransform.rect); markerPosList[1].anchoredPosition = ScreenLocate.quadUnityVectorList[1].pixelToLocalPosition_AnchorCenter(Vector2.one, canvasRectTransform.rect); markerPosList[2].anchoredPosition = ScreenLocate.quadUnityVectorList[3].pixelToLocalPosition_AnchorCenter(Vector2.one, canvasRectTransform.rect); markerPosList[3].anchoredPosition = ScreenLocate.quadUnityVectorList[2].pixelToLocalPosition_AnchorCenter(Vector2.one, canvasRectTransform.rect); SetMarkerRectanglePoints(linePosConversion(markerPosList[0].localPosition, markerPosList[1].localPosition, markerPosList[2].localPosition, markerPosList[3].localPosition)); } } /// /// 绘制线 /// /// void SetMarkerPointesPos(List screenPositions) { Debug.Log("[ScreenLocate] SetMarkerPointesPos :"); markerPosList[0].anchoredPosition = screenPositions[0]; markerPosList[1].anchoredPosition = screenPositions[1]; markerPosList[2].anchoredPosition = screenPositions[2]; markerPosList[3].anchoredPosition = screenPositions[3]; SetMarkerRectanglePoints(linePosConversion(markerPosList[0].localPosition, markerPosList[1].localPosition, markerPosList[2].localPosition, markerPosList[3].localPosition)); } /// /// 重置marker 绘线框 /// void ResetMarkerPointesPos() { Debug.Log("[ScreenLocate] ResetMarkerPointesPos :"); // 获取屏幕的四个角的像素坐标 Vector2 bottomLeft = new Vector2(0, 0); // 将屏幕像素坐标转换为 Canvas 的局部坐标 Vector2 localBottomLeft; RectTransformUtility.ScreenPointToLocalPointInRectangle(canvasRectTransform, bottomLeft, null, out localBottomLeft); int _x = Mathf.FloorToInt(Mathf.Abs(localBottomLeft.x)), _y = Mathf.FloorToInt(Mathf.Abs(localBottomLeft.y)); markerPosList[0].anchoredPosition = new Vector3(-_x, -_y, 0); //Bottom Left markerPosList[1].anchoredPosition = new Vector3(_x, -_y, 0); //Bottom Right markerPosList[2].anchoredPosition = new Vector3(_x, _y, 0); //Top Right markerPosList[3].anchoredPosition = new Vector3(-_x, _y, 0); //Top Left SetMarkerRectanglePoints(linePosConversion(markerPosList[0].localPosition, markerPosList[1].localPosition, markerPosList[2].localPosition, markerPosList[3].localPosition)); } void SetMarkerRectanglePoints(List screenPositions) { markerPointsLine.SetLine(screenPositions); } #endregion }