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 UnityEngine.SceneManagement; using o0InfraredLocate.ZIM; using AdaptUI; using AppUI.Manager.View; namespace AppUI.View.Infrared { public enum ScreenPositioningStep { None, // Start,//开始界面 AutoEnd,//自动定位结束后界面 AutoEndFail,//自动定位结束后没有数据界面 Manual,//手动界 Successful,//四角消灭界面 } public class LinePosition { public int index; public List pos; } public class InfraredScreenPositioningView : MonoBehaviour { [SerializeField] RectTransform canvasRectTransform; [SerializeField] RectTransform draggableParent; [SerializeField] RectTransform pointsParent; [SerializeField] RectTransform pos1; [SerializeField] RectTransform pos2; [SerializeField] RectTransform pos3; [SerializeField] RectTransform pos4; //画线时候的点偏移量 float offset = 10; [Tooltip("勾选后拖拽点与 Line 顶点均按控件中心对齐")] [SerializeField] bool useCenterPivot = false; [SerializeField] Line line; List oldLinePosition; Vector3 beginPos; Vector3 endPos; [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] Line maskLine_ipad; [SerializeField] RawImage rawImage; [Tooltip("Demo测试时候显示")] [SerializeField] RectTransform crosshair; [SerializeField] RectTransform crosshairRed; [Tooltip("存在校准数据时候显示")] [SerializeField] LineGenerator CurrentUILineGenerator;//开始显示屏幕线条 [Header("Start Layout Group")] [SerializeField] GameObject LayoutStart; [Header("AutoEnd Layout Group")] [SerializeField] GameObject LayoutAutoEnd; [SerializeField] Button AutoEndConfirmBtn; [SerializeField] Sprite ConfirmBtnBg; [SerializeField] Color ConfirmBtnNormalColor = Color.white; [SerializeField] Color ConfirmBtnHideColor = new Color(181f / 255f, 181f / 255f, 181f / 255f, 1f); [SerializeField] GameObject TipCalibrationFailedIphone; [Tooltip("没有存在校准数据时候显示 ipad 提示失败")] [SerializeField] GameObject TipCalibrationFailedIpad; [Header("AutoEndFail Layout Group")] [SerializeField] GameObject LayoutAutoFail; [SerializeField] Button AutoEndFailConfirmBtn; [Header("Manual Layout Group")] [SerializeField] GameObject LayoutManual; [SerializeField] Line manualLine;//手动页面的line [Header("Successful Layout Group")] [SerializeField] GameObject LayoutSuccessful; //[Tooltip("没有存在校准数据时候显示提示失败")] //[SerializeField] //GameObject AutoCalibrationFailedTip; 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; SyncDraggableCenterMode(); } void Start() { //获取InfraredDemo infraredDemo = InfraredDemo._ins; doLocateAuto = false; 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(); } //更新start相关ui UpdateStartUI(); //记录操作的位置信息 oldLinePosition = new List(); SetLinePos(); //相机感光度 if (infraredDemo) { ////重置偏移量 //infraredDemo.ResetCenterOffset(); //////重置识别点 ////ScreenLocate.Main.ScreenIdentification.ClearQuadCache(); //////清除一下记录的点 ////ScreenLocate.quadUnityVectorList.Clear(); //infraredDemo.ResetPositioningData(); //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); if (CurrentUILineGenerator.Points.Length != 0) { //显示maskline setMaskLineByDeviceType(false); } else { //显示maskline switchMaskLineByDeviceType(true); } } } private void OnDestroy() { } 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); } else if (InfraredDemo.running) { //渲染相机画面 Texture texture = InfraredDemo.infraredCameraHelper.GetCameraTexture(); if (rawImage.texture == null || texture.GetNativeTexturePtr() != rawImage.texture.GetNativeTexturePtr()) { rawImage.texture = 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.Successful) { 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); } } } /// /// 根据平台显示不同的maskLine /// /// void switchMaskLineByDeviceType(bool bShow) { if (DeviceTypeHelper.DetectDeviceType() == DeviceTypeHelper.DeviceType.iPhone) { maskLine.gameObject.SetActive(bShow); maskLine_ipad.gameObject.SetActive(!bShow); } else { maskLine.gameObject.SetActive(!bShow); maskLine_ipad.gameObject.SetActive(bShow); } } void setMaskLineByDeviceType(bool bShow) { if (DeviceTypeHelper.DetectDeviceType() == DeviceTypeHelper.DeviceType.iPhone) { maskLine.gameObject.SetActive(bShow); } else { maskLine_ipad.gameObject.SetActive(bShow); } } /// /// 根据 平台返回 对应的 ScreenPositions /// /// List getMaskLinePositionsByDeviceType() { return DeviceTypeHelper.DetectDeviceType() == DeviceTypeHelper.DeviceType.iPhone ? maskLine.ScreenPositions : maskLine_ipad.ScreenPositions; } /// /// 设置校准结束时候的定位按钮 /// /// public void SetAutoConfirmBtnActive(bool active) { if (AutoEndConfirmBtn == null) return; Image btnImage = AutoEndConfirmBtn.GetComponent(); if (btnImage == null) return; // 根据 active 状态切换按钮外观 if (active) { btnImage.color = ConfirmBtnNormalColor; if (ConfirmBtnBg != null) { btnImage.sprite = ConfirmBtnBg; } AutoEndConfirmBtn.interactable = true; } else { btnImage.color = ConfirmBtnHideColor; btnImage.sprite = null; // 去掉背景图 AutoEndConfirmBtn.interactable = false; } } /// /// 根据enum操作ui /// /// public void SetScreenPositioningStepState(ScreenPositioningStep step = ScreenPositioningStep.None) { curStepView = step; AllScreenPositioningStepFalse(); TipCalibrationFailedIphone.SetActive(false); TipCalibrationFailedIpad.SetActive(false); //AutoCalibrationFailedTip.SetActive(false); QuadrilateralInCamera screenAuto = ScreenLocate.Main.ScreenIdentification.QuadAuto; switch (step) { case ScreenPositioningStep.Start: //maskLine.SetDrawMask(true); switchMaskLineByDeviceType(true); LayoutStart.SetActive(true); UpdateStartUI(); break; case ScreenPositioningStep.AutoEnd: //switchMaskLineByDeviceType(true); setMaskLineByDeviceType(false); LayoutAutoEnd.SetActive(true); pointsParent.gameObject.SetActive(false); CurrentUILineGenerator.enabled = true; if (screenAuto == null) { //不存在数据,走流程2 SetAutoConfirmBtnActive(false); if (DeviceTypeHelper.DetectDeviceType() == DeviceTypeHelper.DeviceType.iPhone) { TipCalibrationFailedIphone.SetActive(true); } else { TipCalibrationFailedIpad.SetActive(true); } } else { //存在数据,显示确认按钮 SetAutoConfirmBtnActive(true); } break; case ScreenPositioningStep.AutoEndFail: switchMaskLineByDeviceType(true); LayoutAutoFail.SetActive(true); CurrentUILineGenerator.enabled = true; break; case ScreenPositioningStep.Manual: setMaskLineByDeviceType(false); SaveStartOldLinePosition(); perStepView = ScreenPositioningStep.Manual; bMarkerFinish = false; LayoutManual.SetActive(true); bAuto = false; doLocateAuto = false; draggableParent.gameObject.SetActive(true); pointsParent.gameObject.SetActive(false); //隐藏识别后的线 CurrentUILineGenerator.enabled = false; if (screenAuto == null) { //不存在数据 onResetByMaskLine(); } break; case ScreenPositioningStep.Successful: setMaskLineByDeviceType(false); LayoutSuccessful.SetActive(true); pointsParent.gameObject.SetActive(false); CurrentUILineGenerator.enabled = false; if (SB_EventSystem.ins && !SB_EventSystem.ins.simulateMouseIsAwaked) { SB_EventSystem.ins.AwakenSimulateMouse(); } break; } } void AllScreenPositioningStepFalse() { LayoutStart.SetActive(false); //LayoutMarker.SetActive(false); LayoutManual.SetActive(false); LayoutAutoEnd.SetActive(false); LayoutAutoFail.SetActive(false); //LayoutLightCtrl.SetActive(false); LayoutSuccessful.SetActive(false); onClearSuccessfullLineGenerator(); } /// /// 开始页面时候ui /// void UpdateStartUI() { pointsParent.gameObject.SetActive(false); CurrentUILineGenerator.enabled = true; if (ScreenLocate.quadUnityVectorList.Count == 0) { } else { } } public void OnClick_Back() { AudioMgr.ins.PlayBtn(); ViewManager.HideView(UIViewType.InfraredScreenPositioningView); } public void OnClick_PositioningFailedDemonstration() { Debug.Log("失败演示Todo."); } /// /// 返回最开始页面 /// public void OnClick_BackLayoutStart() { ClearPointsData(); SetScreenPositioningStepState(ScreenPositioningStep.Start); } void ClearPointsData() { //重置中心点0 infraredDemo?.ResetCenterOffset(); //清除白线数据 infraredDemo?.ResetPositioningData(); //上面应该清空了 ScreenLocate.Main.ScreenIdentification.QuadAuto onClearCurrentUILineGenerator(); } /// /// 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_Auto() { bAuto = true; doLocateAuto = true; if (enterFromZimWebCamera) { ScreenLocate _screenLocate = FindAnyObjectByType(); _screenLocate.EnterScreenLocateManualAuto(); return; } if (InfraredDemo.running) { InfraredDemo.infraredCameraHelper.EnterScreenLocateManualAuto(); } } /// /// 进入手动界面 /// public void OnClick_EnterManual() { SetScreenPositioningStepState(ScreenPositioningStep.Manual); } /// /// 进入最后四角消灭页面 /// public void OnClick_Successful() { SetScreenPositioningStepState(ScreenPositioningStep.Successful); } /// /// 切换成手动方式 /// public void onHandMovement() { bAuto = false; doLocateAuto = false; draggableParent.gameObject.SetActive(true); pointsParent.gameObject.SetActive(false); mask.SetActive(false); } /// /// 自动识别后同步 /// public void SyncScreenPosition() { Vector2 texSize = ScreenLocate.Main.getUVCCameraInfoSize; Debug.Log("texSize:" + texSize + " = " + canvasRectTransform.rect); SyncQuadUnityVectorListToPos(); RefreshLineFromHandles(); //SyncQuadUnityVectorListToMarkerPointesPos(); //显示提示 //pointMarker.ShowHintImageParent(true); //AutoEndConfirmBtn.interactable = true; SetAutoConfirmBtnActive(true); //屏幕变化情况下。同步修改对应的line //设置两个线段 QuadrilateralInCamera screenAuto = ScreenLocate.Main.ScreenIdentification.QuadAuto; QuadrilateralInCamera screenSemiAuto = ScreenLocate.Main.ScreenIdentification.QuadSemiAuto; if (screenAuto != null) { //Debug.Log("[校准流程]Successful自动识别screenAuto信息 ------------ "); //if (AutoCalibrationFailedTip != null) // AutoCalibrationFailedTip.SetActive(false); CurrentUILineGenerator.Points = infraredDemo.ConvertQuadToPoints(screenAuto, texSize); //FirstUILineGenerator.Points = infraredDemo.ConvertQuadToPoints(screenAuto, texSize); //如果是开始页面进行自动定位的 if (curStepView == ScreenPositioningStep.Start) { if (curStepView != ScreenPositioningStep.AutoEnd) { SetScreenPositioningStepState(ScreenPositioningStep.AutoEnd); } } } else { //if (AutoCalibrationFailedTip != null) // AutoCalibrationFailedTip.SetActive(true); 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) { RefreshLineFromHandles(); } //点击拖拽的结束位置 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(); RefreshLineFromHandles(); } void SyncDraggableCenterMode() { SyncDraggableCenterMode(pos1); SyncDraggableCenterMode(pos2); SyncDraggableCenterMode(pos3); SyncDraggableCenterMode(pos4); } void SyncDraggableCenterMode(RectTransform handle) { if (handle == null) return; DraggablePolygonPoint draggable = handle.GetComponent(); if (draggable != null) draggable.SetUseCenterDrag(useCenterPivot); } Vector3 GetHandleLocalPosition(RectTransform handle) { if (!useCenterPivot) return handle.localPosition; return handle.localPosition + (Vector3)handle.rect.center; } void SetHandleLocalPosition(RectTransform handle, Vector3 localPos) { handle.localPosition = useCenterPivot ? localPos - (Vector3)handle.rect.center : localPos; } Vector2 GetHandleAnchoredPosition(RectTransform handle) { if (!useCenterPivot) return handle.anchoredPosition; return handle.anchoredPosition + (Vector2)handle.rect.center; } void SetHandleAnchoredPosition(RectTransform handle, Vector2 anchoredPos) { handle.anchoredPosition = useCenterPivot ? anchoredPos - (Vector2)handle.rect.center : anchoredPos; } void RefreshLineFromHandles() { SetRectanglePoints(linePosConversion( GetHandleLocalPosition(pos1), GetHandleLocalPosition(pos2), GetHandleLocalPosition(pos3), GetHandleLocalPosition(pos4))); } static Vector2 GetCornerRecordPivot(int index) { switch (index) { case 0: return new Vector2(0, 0); case 1: return new Vector2(1, 0); case 2: return new Vector2(1, 1); case 3: return new Vector2(0, 1); default: return new Vector2(0.5f, 0.5f); } } void RecordHandleLocatePoint(RectTransform handle, int index) { Vector2 pivot = useCenterPivot ? new Vector2(0.5f, 0.5f) : GetCornerRecordPivot(index); RecordLocatePoint(handle, pivot); } 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(GetHandleLocalPosition(pos1)); screenPositions.Add(GetHandleLocalPosition(pos2)); screenPositions.Add(GetHandleLocalPosition(pos3)); screenPositions.Add(GetHandleLocalPosition(pos4)); LinePosition linePosition = new LinePosition(); linePosition.index = oldLinePosition.Count; linePosition.pos = screenPositions; oldLinePosition.Add(linePosition); } /// /// 记录一个开始位置 /// void SaveStartOldLinePosition() { oldLinePosition.Clear(); //记录一个操作点的操作位置 List screenPositions = new List(); screenPositions.Add(GetHandleLocalPosition(pos1)); screenPositions.Add(GetHandleLocalPosition(pos2)); screenPositions.Add(GetHandleLocalPosition(pos3)); screenPositions.Add(GetHandleLocalPosition(pos4)); 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(); if (useCenterPivot) { _screenPositions.Add(_pos1); _screenPositions.Add(_pos2); _screenPositions.Add(_pos3); _screenPositions.Add(_pos4); return _screenPositions; } //点为负数的增大 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); // 删除最后一个元素 SetHandleLocalPosition(pos1, lastElement_second.pos[0]); SetHandleLocalPosition(pos2, lastElement_second.pos[1]); SetHandleLocalPosition(pos3, lastElement_second.pos[2]); SetHandleLocalPosition(pos4, lastElement_second.pos[3]); //设置线段的点 RefreshLineFromHandles(); } } //是不是从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(); ViewManager.HideView(UIViewType.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 { ViewManager.HideView(UIViewType.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)); SetHandleAnchoredPosition(pos1, new Vector2(-_x, -_y)); //Bottom Left SetHandleAnchoredPosition(pos2, new Vector2(_x, -_y)); //Bottom Right SetHandleAnchoredPosition(pos3, new Vector2(_x, _y)); //Top Right SetHandleAnchoredPosition(pos4, new Vector2(-_x, _y)); //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) { //如果是开始页面进行自动定位的失败的 if (curStepView != ScreenPositioningStep.AutoEndFail) { SetScreenPositioningStepState(ScreenPositioningStep.AutoEndFail); } //AutoEndConfirmBtn.interactable = false; SetAutoConfirmBtnActive(false); } } /// /// 根据MaskLine 重置 可拖拽的 line 部分数据 /// public void onResetByMaskLine() { oldLinePosition.Clear(); List _markLine = getMaskLinePositionsByDeviceType();// maskLine.ScreenPositions SetHandleAnchoredPosition(pos1, _markLine[0] + new Vector2(20, 15));//Bottom Left SetHandleAnchoredPosition(pos2, _markLine[1] + new Vector2(-20, 15)); //Bottom Right SetHandleAnchoredPosition(pos3, _markLine[2] + new Vector2(-10, -15)); //Top Right SetHandleAnchoredPosition(pos4, _markLine[3] + new Vector2(10, -15));//Top Left //设置一次位置 SetLinePos(); } /// /// 标准四个点 /// /// /// public void onManualNewPos(int index, Vector3 pos) { Debug.Log("pos end: " + pos); if (index == 0) SetHandleLocalPosition(pos1, pos); else if (index == 1) SetHandleLocalPosition(pos2, pos); else if (index == 2) SetHandleLocalPosition(pos3, pos); else if (index == 3) SetHandleLocalPosition(pos4, 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(); //直接设置后进入下一步 OnSecondResult(); //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; RecordHandleLocatePoint(pos1, 0); RecordHandleLocatePoint(pos2, 1); RecordHandleLocatePoint(pos3, 2); RecordHandleLocatePoint(pos4, 3); 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; RecordHandleLocatePoint(pos1, 0); RecordHandleLocatePoint(pos2, 1); RecordHandleLocatePoint(pos3, 2); RecordHandleLocatePoint(pos4, 3); _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(GetHandleAnchoredPosition(pos1)); screenPositions.Add(GetHandleAnchoredPosition(pos2)); screenPositions.Add(GetHandleAnchoredPosition(pos3)); screenPositions.Add(GetHandleAnchoredPosition(pos4)); 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(); SetHandleAnchoredPosition(pos1, posList[0]); SetHandleAnchoredPosition(pos2, posList[1]); SetHandleAnchoredPosition(pos3, posList[2]); SetHandleAnchoredPosition(pos4, posList[3]); RefreshLineFromHandles(); } } #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 最后选择算法处理UI //选择全自动结果后进入游戏 void OnFirstResult() { QuadrilateralInCamera screenAuto = ScreenLocate.Main.ScreenIdentification.QuadAuto; if (screenAuto == null) { Debug.Log("校准结果为空!"); return; } ScreenLocate.Main.SelectScreenAfterLocate(ScreenLocate.ScreenIdentificationTag.Auto); UpdateQuadUnityVectorList(); onCompelete(); } //选择半自动结果 //void OnSecondResult() //{ // ScreenLocate.Main.SelectScreenAfterLocate(ScreenLocate.ScreenIdentificationTag.SemiAuto); // UpdateQuadUnityVectorList(); // onCompelete(); //} //选择手动定位结果 void OnSecondResult() { ScreenLocate.Main.SelectScreenAfterLocate(ScreenLocate.ScreenIdentificationTag.Manual); UpdateQuadUnityVectorList(); onCompelete(); } public void onCompelete() { if (enterFromZimWebCamera) { SaveLocalPos(); ViewManager.HideView(UIViewType.InfraredScreenPositioningView); return; } EnterGame(); //存储一次节点 SaveLocalPos(); } void EnterGame() { //跳转入界面 AudioMgr.ins.PlayBtn(); OnClick_Successful(); //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 // { // ViewManager.HideView(UIViewType.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)); SetHandleAnchoredPosition(pos1, ScreenLocate.quadUnityVectorList[0].pixelToLocalPosition_AnchorCenter(Vector2.one, canvasRectTransform.rect)); SetHandleAnchoredPosition(pos2, ScreenLocate.quadUnityVectorList[1].pixelToLocalPosition_AnchorCenter(Vector2.one, canvasRectTransform.rect)); SetHandleAnchoredPosition(pos4, ScreenLocate.quadUnityVectorList[2].pixelToLocalPosition_AnchorCenter(Vector2.one, canvasRectTransform.rect)); SetHandleAnchoredPosition(pos3, ScreenLocate.quadUnityVectorList[3].pixelToLocalPosition_AnchorCenter(Vector2.one, canvasRectTransform.rect)); } //这个脚本存在时候。任何切换操作都直接处理删除 //void OnSceneUnloaded(Scene scene) //{ // ViewManager.HideView(ViewManager2.Path_ConnectGuidanceView); // ViewManager.HideView(UIViewType.InfraredScreenPositioningView); //} //void OnEnable() //{ // SceneManager.sceneUnloaded += OnSceneUnloaded; //} //void OnDisable() //{ // SceneManager.sceneUnloaded -= OnSceneUnloaded; //} #endregion #region 判断点是否在 quad 内部 //判断maskline public bool IsPointInMaskLine(Vector2 point) { return IsPointInQuad(point, getMaskLinePositionsByDeviceType());// 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 四角消灭处理部分 public int collisionCount = 0; public void SetCollisionEvent() { if (collisionCount < 3) { collisionCount++; } else { StartCoroutine(TransitionToCalibrationAfterCollision()); } } IEnumerator TransitionToCalibrationAfterCollision() { if (SB_EventSystem.ins) { //切换设备时候清除一下选中状态,避免鼠标还在UI上有选中状态 SB_EventSystem.ins.simulateMouse?.ClearSelection(); //SB_EventSystem.ins.mouseConfirm?.Hide(); //if (SB_EventSystem.ins.simulateMouseIsAwaked) //{ // SB_EventSystem.ins.AwakenSimulateMouse(); //} } yield return null; ViewManager.HideView(UIViewType.DeviceArcheryView); ViewManager.HideView(UIViewType.DeviceGunView); ViewManager.HideView(UIViewType.InfraredScreenPositioningView); ViewManager.ShowView(UIViewType.CalibrationView); } #endregion } }