Mesh共用、顶点合并

This commit is contained in:
zhangXQ 2021-02-28 11:38:29 +08:00
parent e5e28afc3f
commit 341b9efe3c
9 changed files with 229 additions and 159 deletions

View File

@ -11,28 +11,34 @@ namespace NwGeoExporter
{
public class CustomExporter : InwSimplePrimitivesCB
{
private TransformM transform3D;
//private TransformM transform3D;
public CustomExporter()
{
Triangles = new List<Triangle>();
}
public CustomExporter(TransformM transform3D):this()
{
this.transform3D = transform3D;
}
//public CustomExporter(TransformM transform3D):this()
//{
// this.transform3D = transform3D;
//}
public List<Triangle> Triangles { get; set; }
public void Triangle(InwSimpleVertex v1, InwSimpleVertex v2, InwSimpleVertex v3)
{
//var vertices = new PointM[]
// {
// transform3D.OfPoint(new PointM(v1)),
// transform3D.OfPoint(new PointM(v2)),
// transform3D.OfPoint(new PointM(v3)),
// };
var vertices = new PointM[]
{
transform3D.OfPoint(new PointM(v1)),
transform3D.OfPoint(new PointM(v2)),
transform3D.OfPoint(new PointM(v3)),
};
{
new PointM(v1),
new PointM(v2),
new PointM(v3),
};
var normals = new VectorM[]
{
new VectorM(v1),
@ -40,7 +46,7 @@ namespace NwGeoExporter
new VectorM(v3),
};
//Triangles.Add(new Triangle(v1,v2,v3));
Triangles.Add(new Triangle(normals,vertices));
Triangles.Add(new Triangle(normals, vertices));
}
public void Line(InwSimpleVertex v1, InwSimpleVertex v2)

View File

@ -22,24 +22,8 @@ namespace NwGeoExporter.Models
[JsonIgnore]
public TransformM Transform { get; set; }
///// <summary>
///// 转换-序列化(列主序)
///// </summary>
//public double[] transform
//{
// get
// {
// return new double[]
// {
// Transform.BasicX.X,Transform.BasicX.Y,Transform.BasicX.Z,0
// ,Transform.BasicY.X,Transform.BasicY.Y,Transform.BasicY.Z,0
// ,Transform.BasicZ.X,Transform.BasicZ.Y,Transform.BasicZ.Z,0
// ,Transform.Origin.X,Transform.Origin.Y,Transform.Origin.Z,1
// };
// }
//}
/// <summary>
/// 转换-序列化(主序)
/// 转换-序列化(列主序)
/// </summary>
public double[] transform
{
@ -50,10 +34,11 @@ namespace NwGeoExporter.Models
Transform.BasicX.X,Transform.BasicX.Y,Transform.BasicX.Z,0
,Transform.BasicY.X,Transform.BasicY.Y,Transform.BasicY.Z,0
,Transform.BasicZ.X,Transform.BasicZ.Y,Transform.BasicZ.Z,0
,Transform.Origin.X,Transform.Origin.Y,Transform.Origin.Z,1
,Transform.Origin.X.Feet2Mm(),Transform.Origin.Y.Feet2Mm(),Transform.Origin.Z.Feet2Mm(),1
};
}
}
/// <summary>
/// 是否可见
/// </summary>

View File

@ -15,7 +15,7 @@ namespace NwGeoExporter.Models
/// 顶点数组-序列化数据
/// </summary>
public double[] vertices { get => VerticeList.SelectMany(x => new List<double> { x.X.Feet2Mm(), x.Y.Feet2Mm(), x.Z.Feet2Mm() }).ToArray(); }
//public double[] vertices { get => VerticeList.SelectMany(x => new List<double> { x.X, x.Y, x.Z }).ToArray(); }
/// <summary>
/// 顶点索引-序列化数据
/// </summary>
@ -71,35 +71,63 @@ namespace NwGeoExporter.Models
{
for (int i = 0; i < triangle.Vertices.Length; i++)
{
// bool isHandle = false;
// for (int j = 0; j < VerticeList.Count; j++)
// {
// if (VerticeList[j] == triangle.vertices[i])
// {
// //拿到索引集合中与当前顶点值一样的索引
// List<int> indexList = IndiceList.FindIndexs(x => x == j);
bool isHandle = false;
//相同的顶点位置的索引
List<int> indexList = VerticeList.FindIndexs(x => x == triangle.Vertices[i]);
//当前三角面片顶点法向
VectorM currentVector = triangle.Normals[i];
//最后一次合并的索引
int lastMergeIndex = 0;
while (indexList.Count != 0)
{
//判断索引内是否需要合并的顶点
var index = indexList.FindIndex(x => NormalList[x].AngelTo(currentVector).ToAngle() - 90 > 0.1);
if (index == -1)
{
break;
}
else if (!isHandle)//第一次
{
NormalList[indexList[index]] = (currentVector + NormalList[indexList[index]]).Normalize();
currentVector = NormalList[indexList[index]];
lastMergeIndex = indexList[index];
indexList.RemoveAt(index);
isHandle = true;
}
else//原来顶点位置一致的与合并后的顶点进行比较
{
int removeIndex = Math.Max(lastMergeIndex, indexList[index]);
lastMergeIndex = Math.Min(lastMergeIndex, indexList[index]);
// //TODO考虑多个的情况
// //第几个需要跟当前顶点法向进行平均
// int index = indexList.FindIndex(x => NormalList[x]
// .AngelTo(triangle.normals[i]).ToAngle() - 90 > 0.1);
// //有遇到顶点法线平均
// if (index != -1)
// {
// NormalList[j] = (triangle.normals[i] + NormalList[j]).Normalize();
// isHandle = true;
// break;
// }
// }
// }
// if (!isHandle)
// {
//添加顶点以及顶点法向以及对应的索引
VerticeList.Add(triangle.Vertices[i]);
NormalList.Add(triangle.Normals[i]);
IndiceList.Add(VerticeList.Count - 1);
//重置索引
for (int k = 0; k < IndiceList.Count; k++)
{
if (IndiceList[k] > removeIndex)
{
IndiceList[k]--;
}
else if (IndiceList[k] == removeIndex)
{
IndiceList[k] = lastMergeIndex;
}
}
//删除不需要的顶点和法向
NormalList.RemoveAt(removeIndex);
VerticeList.RemoveAt(removeIndex);
}
}
if (!isHandle)
{
//添加顶点以及顶点法向以及对应的索引
VerticeList.Add(triangle.Vertices[i]);
NormalList.Add(triangle.Normals[i]);
IndiceList.Add(VerticeList.Count - 1);
}else
{
IndiceList.Add(lastMergeIndex);
}
}
//}
}
public void AddTriangles(IEnumerable<Triangle> triangles)

View File

@ -42,7 +42,7 @@ namespace NwGeoExporter.Models
{
if (obj is PointM pm)
{
if (pm.X.Round(6) == X.Round(6) && pm.Y.Round(6) == Y.Round(6) && pm.Z.Round(6) == Z.Round(6))
if (pm.X.Round(4) == X.Round(4) && pm.Y.Round(4) == Y.Round(4) && pm.Z.Round(4) == Z.Round(4))
return true;
}
return false;

View File

@ -27,7 +27,7 @@ namespace NwGeoExporter.Models
Origin = new PointM(),
};
}
private InwLTransform3f3 inwTransform;
//private InwLTransform3f3 inwTransform;
private TransformM()
{
@ -44,31 +44,31 @@ namespace NwGeoExporter.Models
BasicY = new VectorM(matrixElements[4], matrixElements[5], matrixElements[6]);
BasicZ = new VectorM(matrixElements[8], matrixElements[9], matrixElements[10]);
Origin = new PointM(matrixElements[12], matrixElements[13], matrixElements[14]);
this.inwTransform = inwTransform;
}
public PointM OfPoint(PointM point)
{
double[] matrixElements = ((Array)(object)inwTransform.Matrix).ToArray<double>();
double x = point.X;
double y = point.Y;
double z = point.Z;
double w = matrixElements[3] * x + matrixElements[7] * y + matrixElements[11] * z + matrixElements[15];
return new PointM(
(matrixElements[0] * x + matrixElements[4] * y + matrixElements[8] * z + matrixElements[12]) / w,
(matrixElements[1] * x + matrixElements[5] * y + matrixElements[9] * z + matrixElements[13]) / w,
(matrixElements[2] * x + matrixElements[6] * y + matrixElements[10] * z + matrixElements[14]) / w);
//this.inwTransform = inwTransform;
}
//public PointM OfPoint(PointM point)
//{
// double[] matrixElements = ((Array)(object)inwTransform.Matrix).ToArray<double>();
// double x = point.X;
// double y = point.Y;
// double z = point.Z;
// return
// new PointM(
// BasicX.X * x + BasicY.X * y + BasicZ.X * z + Origin.X,
// BasicX.Y * x + BasicY.Y * y + BasicZ.Y * z + Origin.Y,
// BasicX.Z * x + BasicY.Z * y + BasicZ.Z * z + Origin.Z
// );
// double w = matrixElements[3] * x + matrixElements[7] * y + matrixElements[11] * z + matrixElements[15];
// return new PointM(
//(matrixElements[0] * x + matrixElements[4] * y + matrixElements[8] * z + matrixElements[12]) / w,
//(matrixElements[1] * x + matrixElements[5] * y + matrixElements[9] * z + matrixElements[13]) / w,
//(matrixElements[2] * x + matrixElements[6] * y + matrixElements[10] * z + matrixElements[14]) / w);
//}
public PointM OfPoint(PointM point)
{
double x = point.X;
double y = point.Y;
double z = point.Z;
return
new PointM(
BasicX.X * x + BasicY.X * y + BasicZ.X * z + Origin.X,
BasicX.Y * x + BasicY.Y * y + BasicZ.Y * z + Origin.Y,
BasicX.Z * x + BasicY.Z * y + BasicZ.Z * z + Origin.Z
);
}
}
}

View File

@ -1,4 +1,5 @@
using System;
using Autodesk.Navisworks.Api;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
@ -41,7 +42,20 @@ namespace NwGeoExporter.NwEx
}
return -1;
}
/// <summary>
/// 转ModelItemCollection
/// </summary>
/// <param name="items"></param>
/// <returns></returns>
public static ModelItemCollection ToCollection(this IEnumerable<ModelItem> items)
{
ModelItemCollection collection = new ModelItemCollection();
foreach (var it in items)
{
collection.Add(it);
}
return collection;
}
/// <summary>
/// 找到所有的索引
/// </summary>
@ -61,7 +75,7 @@ namespace NwGeoExporter.NwEx
indexList.Add(i);
}
}
return indexList.Count == 0 ? null : indexList;
return indexList.Count == 0 ? new List<int>() : indexList;
}
}
}

View File

@ -42,6 +42,11 @@ namespace NwGeoExporter
//获取项目树中的子项
var modelItemColl = ModelItemUtils.GetModelItems(doc);
//分组(子项中有相同几何数据的分为一组)
var itemGroup = modelItemColl.GroupBy(x => x, new BaseComparer<ModelItem>((x, y) => x.IsSameInstance(y))).Select(x => x.ToList()).ToList();
//取其中一个
modelItemColl = itemGroup.Select(x => x.First()).ToCollection();
//转换成选择集
COMApi.InwOpSelection selItemColl =
ComBridge.ToInwOpSelection(modelItemColl);
@ -51,88 +56,91 @@ namespace NwGeoExporter
{
//是否是可载入族
bool isInstance = ModelItemUtils.IsRevitInstance(modelItemColl[index].Parent.Parent);
#region Mesh材质
//材质属性
var material = GetMaterial(modelItemColl[index].Parent);
//查找材质索引
int matIndex = materialList.FindIndex(x => x.Equals(material));
if (matIndex == -1)
{
materialList.Add(material);
matIndex = materialList.Count - 1;
}
#endregion
#region Revit元素属性
Dictionary<string, string> elemPropertyDict = new Dictionary<string, string>();
DataPropertyCollection elemPropertyColl = null;
if (isInstance)
{
elemPropertyColl = GetDataPropertys(modelItemColl[index].Parent.Parent, PropertyCategoryName.LcRevitData_Element);
}
else
{
elemPropertyColl = GetDataPropertys(modelItemColl[index].Parent, PropertyCategoryName.LcRevitData_Element);
}
//二级是系统族获取元素属性的方法
foreach (var elemProperty in elemPropertyColl)
{
if (!elemPropertyDict.ContainsKey(elemProperty.CombinedName.ToString()))
elemPropertyDict.Add(elemProperty.CombinedName.ToString(), GetValueString(elemProperty));
}
#endregion
#region ID
string elemID = "";
DataPropertyCollection projectPropertyColl = null;
if (isInstance)
{
projectPropertyColl = GetDataPropertys(modelItemColl[index].Parent.Parent, PropertyCategoryName.LcOaNode);
}
else
{
projectPropertyColl = GetDataPropertys(modelItemColl[index].Parent, PropertyCategoryName.LcOaNode);
}
foreach (var projectProperty in projectPropertyColl)
{
if (projectProperty.Name == "LcOaNodeGuid")
{
elemID = GetValueString(projectProperty);
}
}
#endregion
#region Mesh
Mesh mesh = new Mesh(matIndex);
TransformM transform3D = null;
Mesh mesh = null;
int instanceIndex = 0;
foreach (COMApi.InwOaFragment3 frag in path.Fragments())
{
//if (transform3D == null)
//{
InwLTransform3f3 localToWorld = (InwLTransform3f3)frag.GetLocalToWorldMatrix();
transform3D = new TransformM(localToWorld);
//}
CustomExporter customExporter = new CustomExporter(transform3D);
// generate the primitives
frag.GenerateSimplePrimitives(COMApi.nwEVertexProperty.eNORMAL, customExporter);
mesh.AddTriangles(customExporter.Triangles);
}
meshList.Add(mesh);
#endregion
#region Revit元素属性
Dictionary<string, string> elemPropertyDict = new Dictionary<string, string>();
DataPropertyCollection elemPropertyColl = null;
if (isInstance)
{
elemPropertyColl = GetDataPropertys(itemGroup[index][instanceIndex].Parent.Parent, PropertyCategoryName.LcRevitData_Element);
}
else
{
elemPropertyColl = GetDataPropertys(itemGroup[index][instanceIndex].Parent, PropertyCategoryName.LcRevitData_Element);
}
//二级是系统族获取元素属性的方法
foreach (var elemProperty in elemPropertyColl)
{
if (!elemPropertyDict.ContainsKey(elemProperty.CombinedName.ToString()))
elemPropertyDict.Add(elemProperty.CombinedName.ToString(), GetValueString(elemProperty));
}
#endregion
#region Instance对象
Instance currentInstance = new Instance()
{
id = elemID,
mesh = meshList.Count - 1,
Transform = TransformM.Identify,
visible = 1.0,
info = elemPropertyDict,
};
instanceList.Add(currentInstance);
#region ID
string elemID = "";
DataPropertyCollection projectPropertyColl = null;
if (isInstance)
{
projectPropertyColl = GetDataPropertys(modelItemColl[index].Parent.Parent, PropertyCategoryName.LcOaNode);
}
else
{
projectPropertyColl = GetDataPropertys(modelItemColl[index].Parent, PropertyCategoryName.LcOaNode);
}
foreach (var projectProperty in projectPropertyColl)
{
if (projectProperty.Name == "LcOaNodeGuid")
{
elemID = GetValueString(projectProperty);
}
}
#endregion
InwLTransform3f3 localToWorld = (InwLTransform3f3)frag.GetLocalToWorldMatrix();
var transform3D = new TransformM(localToWorld);
if (mesh == null)
{
#region Mesh材质
//材质属性
var material = GetMaterial(modelItemColl[index].Parent);
//查找材质索引
int matIndex = materialList.FindIndex(x => x.Equals(material));
if (matIndex == -1)
{
materialList.Add(material);
matIndex = materialList.Count - 1;
}
#endregion
mesh = new Mesh(matIndex);
CustomExporter customExporter = new CustomExporter();
// generate the primitives
frag.GenerateSimplePrimitives(COMApi.nwEVertexProperty.eNORMAL, customExporter);
mesh.AddTriangles(customExporter.Triangles);
meshList.Add(mesh);
}
#region Instance对象
Instance currentInstance = new Instance()
{
id = elemID,
mesh = meshList.Count - 1,
Transform = transform3D,
visible = 1.0,
info = elemPropertyDict,
};
#endregion
instanceList.Add(currentInstance);
instanceIndex++;
}
index++;
#endregion
}
NwModel model = new NwModel(instanceList, meshList, materialList);

View File

@ -71,6 +71,7 @@
<Compile Include="NwExporterPlugin.cs" />
<Compile Include="NwEx\IEnumerableEx.cs" />
<Compile Include="NwEx\MathEx.cs" />
<Compile Include="NwUtils\BaseComparer.cs" />
<Compile Include="NwUtils\JsonUtils.cs" />
<Compile Include="NwUtils\ModelUtils.cs" />
<Compile Include="NwUtils\PropertyUtils.cs" />

View File

@ -0,0 +1,28 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
namespace NwGeoExporter.NwUtils
{
public class BaseComparer<T> : IEqualityComparer<T>
{
public BaseComparer(Func<T,T,bool> func)
{
Func = func;
}
private Func<T, T, bool> Func { get; }
public bool Equals(T x, T y)
{
return (bool)Func?.Invoke(x, y);
}
public int GetHashCode(T obj)
{
return 0;
}
}
}