#region 坐标系转化
[System.Serializable]
public class CoordGroup
{
[Header("区域名称/备注")]
public string areaName;
[Header("现实三点(CAD原始坐标)")]
public Vector3 W0, W1, W2;
[Header("对应Unity三点(场景世界坐标)")]
public Vector3 U0, U1, U2;
[Header("坐标系适配配置")]
[Tooltip("自动映射:CAD(XY平面+Z高程) → Unity(XZ平面+Y高程),建筑场景默认开启")]
public bool autoMapAxes = true;
[Tooltip("左手系适配:修正CAD右手系与Unity左手系的镜像偏差,默认开启")]
public bool adaptLeftHand = true;
[HideInInspector] public Matrix4x4 transMatrix;
[HideInInspector] public Matrix4x4 transMatrixInv; // Unity转现实逆矩阵
[HideInInspector] public bool isValid = false;
}
[Header("添加所有独立坐标系区域")]
public CoordGroup[] coordGroups;
/// <summary>
/// 批量计算所有坐标系矩阵
/// </summary>
void BuildAllMatrix()
{
for (int i = 0; i < coordGroups.Length; i++)
{
var group = coordGroups[i];
group.isValid = BuildSingleMatrix(group);
if (!group.isValid)
{
Debug.LogError($"【{group.areaName}】坐标系三点共线,构建失败!");
}
else
{
Debug.Log($"【{group.areaName}】矩阵构建成功");
}
}
}
/// <summary>
/// 构建单个坐标系矩阵(核心适配逻辑已改造)
/// </summary>
bool BuildSingleMatrix(CoordGroup group)
{
// ========== 1. CAD轴向自动对齐Unity ==========
Vector3 w0, w1, w2;
if (group.autoMapAxes)
{
// CAD原始(X,Y,Z) → 对齐Unity轴向:X不变,CAD平面Y→Unity平面Z,CAD高程Z→Unity高程Y
w0 = new Vector3(group.W0.x, group.W0.z, group.W0.y);
w1 = new Vector3(group.W1.x, group.W1.z, group.W1.y);
w2 = new Vector3(group.W2.x, group.W2.z, group.W2.y);
}
else
{
w0 = group.W0;
w1 = group.W1;
w2 = group.W2;
}
// ========== 2. 计算两侧基向量 ==========
// 现实(CAD)侧基向量
Vector3 wAxisX = w1 - w0;
Vector3 wAxisY = w2 - w0;
Vector3 wAxisZ = Vector3.Cross(wAxisX, wAxisY);
// Unity侧基向量
Vector3 uAxisX = group.U1 - group.U0;
Vector3 uAxisY = group.U2 - group.U0;
Vector3 uAxisZ = Vector3.Cross(uAxisX, uAxisY);
// 左手系适配:Unity为左手坐标系,第三轴取反消除镜像
if (group.adaptLeftHand)
{
uAxisZ = -uAxisZ;
}
// 双侧校验三点共线
if (wAxisZ.magnitude < Mathf.Epsilon || uAxisZ.magnitude < Mathf.Epsilon)
return false;
// ========== 3. 构建局部坐标系矩阵 ==========
// 现实坐标系矩阵(已对齐轴向)
Matrix4x4 worldLocal = Matrix4x4.identity;
worldLocal.SetColumn(0, new Vector4(wAxisX.x, wAxisX.y, wAxisX.z, 0));
worldLocal.SetColumn(1, new Vector4(wAxisY.x, wAxisY.y, wAxisY.z, 0));
worldLocal.SetColumn(2, new Vector4(wAxisZ.x, wAxisZ.y, wAxisZ.z, 0));
worldLocal.SetColumn(3, new Vector4(w0.x, w0.y, w0.z, 1));
// Unity坐标系矩阵
Matrix4x4 unityLocal = Matrix4x4.identity;
unityLocal.SetColumn(0, new Vector4(uAxisX.x, uAxisX.y, uAxisX.z, 0));
unityLocal.SetColumn(1, new Vector4(uAxisY.x, uAxisY.y, uAxisY.z, 0));
unityLocal.SetColumn(2, new Vector4(uAxisZ.x, uAxisZ.y, uAxisZ.z, 0));
unityLocal.SetColumn(3, new Vector4(group.U0.x, group.U0.y, group.U0.z, 1));
// ========== 4. 计算最终变换矩阵 ==========
group.transMatrix = unityLocal * worldLocal.inverse;
group.transMatrixInv = group.transMatrix.inverse;
return true;
}
/// <summary>
/// 根据区域下标,CAD现实坐标转Unity坐标
/// </summary>
/// <param name="worldPos">CAD原始坐标(X,Y,Z)</param>
/// <param name="areaIndex">区域下标(从0开始)</param>
public Vector3 WorldToUnity(Vector3 worldPos, int areaIndex)
{
if (areaIndex < 0 || areaIndex >= coordGroups.Length)
{
Debug.LogError("区域下标越界");
return Vector3.zero;
}
var group = coordGroups[areaIndex];
if (!group.isValid)
{
Debug.LogError($"【{group.areaName}】坐标系无效");
return Vector3.zero;
}
// 输入轴向对齐
Vector3 input = worldPos;
if (group.autoMapAxes)
{
input = new Vector3(worldPos.x, worldPos.z, worldPos.y);
}
return group.transMatrix.MultiplyPoint3x4(input);
}
/// <summary>
/// 根据区域名称转换 CAD → Unity
/// </summary>
public Vector3 WorldToUnityByName(Vector3 worldPos, string areaName)
{
foreach (var group in coordGroups)
{
if (group.areaName == areaName && group.isValid)
{
Vector3 input = worldPos;
if (group.autoMapAxes)
{
input = new Vector3(worldPos.x, worldPos.z, worldPos.y);
}
return group.transMatrix.MultiplyPoint3x4(input);
}
}
Debug.LogError($"未找到区域:{areaName}");
return Vector3.zero;
}
/// <summary>
/// 根据区域下标,Unity坐标转CAD现实坐标
/// </summary>
/// <param name="unityPos">Unity场景坐标</param>
/// <param name="areaIndex">区域下标(从0开始)</param>
public Vector3 UnityToWorld(Vector3 unityPos, int areaIndex)
{
if (areaIndex < 0 || areaIndex >= coordGroups.Length)
{
Debug.LogError("区域下标越界");
return Vector3.zero;
}
var group = coordGroups[areaIndex];
if (!group.isValid)
{
Debug.LogError($"【{group.areaName}】坐标系无效");
return Vector3.zero;
}
Vector3 result = group.transMatrixInv.MultiplyPoint3x4(unityPos);
// 输出轴向还原为CAD原始坐标
if (group.autoMapAxes)
{
result = new Vector3(result.x, result.z, result.y);
}
return result;
}
/// <summary>
/// 根据区域名称,Unity坐标转CAD现实坐标
/// </summary>
public Vector3 UnityToWorldByName(Vector3 unityPos, string areaName)
{
foreach (var group in coordGroups)
{
if (group.areaName == areaName && group.isValid)
{
Vector3 result = group.transMatrixInv.MultiplyPoint3x4(unityPos);
if (group.autoMapAxes)
{
result = new Vector3(result.x, result.z, result.y);
}
return result;
}
}
Debug.LogError($"未找到区域:{areaName}");
return Vector3.zero;
}
#endregion