// Magica Cloth.
// Copyright (c) MagicaSoft, 2020-2022.
// https://magicasoft.jp
using System.Collections.Generic;
using UnityEngine;
namespace MagicaReductionMesh
{
///
/// ポリゴンの接続に沿ったリダクション
///
public class PolygonLinkReduction
{
protected MeshData meshData;
private float reductionLength;
///
/// 頂点データ
///
public class Point
{
public MeshData.ShareVertex shareVertex;
///
/// 現在の最近点のポイント(null=なし)
///
public Point nearPoint;
///
/// 現在の最近点ポイントまでの距離
///
public float nearDist;
}
///
/// 頂点データリスト
///
List pointList = new List();
///
/// 共有頂点からの逆引き辞書
///
Dictionary pointDict = new Dictionary();
//=========================================================================================
public PolygonLinkReduction(float length)
{
reductionLength = length;
}
public int PointCount
{
get
{
return pointList.Count;
}
}
//=========================================================================================
///
/// リダクションデータをメッシュデータから構築する
///
///
public void Create(MeshData meshData)
{
this.meshData = meshData;
foreach (var sv in meshData.shareVertexList)
{
AddPoint(sv);
}
// すべてのの最近点を求める
SearchNearPointAll();
}
///
/// リダクション実行
///
public void Reduction()
{
Point p0 = null;
var nlist = new List();
while ((p0 = GetNearPointPair()) != null)
{
// p0にp1をマージする
var p1 = p0.nearPoint;
Debug.Assert(p1 != null);
var sv0 = p0.shareVertex;
var sv1 = p1.shareVertex;
// この2つの頂点を最近点として参照しているリスト
nlist.Clear();
foreach (var sv in sv0.linkShareVertexSet)
nlist.Add(pointDict[sv]);
foreach (var sv in sv1.linkShareVertexSet)
nlist.Add(pointDict[sv]);
nlist.Add(p0); // p0も追加する
// 最近点の参照を切る
foreach (var np in nlist)
{
np.nearPoint = null;
np.nearDist = 100000;
}
// p1を削除
Remove(p1);
p1 = null;
// sv1にsv2をマージ
meshData.CombineVertex(sv0, sv1);
// p0/p1を指していたポイントに対して最近点を再計算する
foreach (var np in nlist)
{
SearchNearPoint(np);
}
}
}
//=========================================================================================
void AddPoint(MeshData.ShareVertex sv)
{
var p = new Point();
p.shareVertex = sv;
pointList.Add(p);
pointDict.Add(sv, p);
}
Point GetPoint(MeshData.ShareVertex sv)
{
if (pointDict.ContainsKey(sv))
return pointDict[sv];
return null;
}
///
/// 頂点をグリッドから削除する
///
///
void Remove(Point p)
{
// データ削除
pointDict.Remove(p.shareVertex);
pointList.Remove(p);
}
//=========================================================================================
///
/// すべての共有頂点の最近接続頂点を調べる
///
void SearchNearPointAll()
{
foreach (var p in pointList)
{
SearchNearPoint(p);
}
}
///
/// 指定頂点の最近接続頂点を調べる
///
///
void SearchNearPoint(Point p)
{
p.nearPoint = null;
p.nearDist = 100000;
var wpos = p.shareVertex.wpos;
foreach (var sv in p.shareVertex.linkShareVertexSet)
{
var dist = Vector3.Distance(wpos, sv.wpos);
if (dist < p.nearDist && dist <= reductionLength)
{
p.nearDist = dist;
p.nearPoint = pointDict[sv];
}
}
}
///
/// 現時点で最も距離が近いポイントペアを返す
///
///
Point GetNearPointPair()
{
float nearDist = 10000;
Point nearPoint = null;
// ※全検索
foreach (var p in pointList)
{
if (p.nearPoint != null && p.nearDist < nearDist)
{
nearDist = p.nearDist;
nearPoint = p;
}
}
return nearPoint;
}
}
}