Mesh共用、顶点合并
This commit is contained in:
parent
e5e28afc3f
commit
341b9efe3c
@ -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)
|
||||
|
@ -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>
|
||||
|
@ -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)
|
||||
|
@ -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;
|
||||
|
@ -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
|
||||
);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -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;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -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);
|
||||
|
@ -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" />
|
||||
|
@ -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;
|
||||
}
|
||||
}
|
||||
}
|
Loading…
Reference in New Issue
Block a user