using PdmSwPlugin.Common.Entity.Pdm;
using SolidWorks.Interop.sldworks;
using SolidWorks.Interop.swconst;
using System;
using System.Collections.Concurrent;
using System.Collections.Generic;
using System.Collections.ObjectModel;
using System.IO;
using System.Linq;
using System.Threading;
using System.Threading.Tasks;
namespace PdmSwPlugin.Common.Util.Pdm
{
public class BomTreeReader
{
public BomTreeReader()
{
factory = LimitedConcurrencyLevelTaskSchedulerMsn.Factory;
}
public TaskFactory factory;
///
/// 全部BOM的平铺List
///
public ConcurrentQueue CacheList { get; private set; } = new ConcurrentQueue();
///
/// 插件展示的TreeBom
///
public ConcurrentQueue TreeList { get; private set; } = new ConcurrentQueue();
///
/// 每次刷新时的缓存
///
private ConcurrentDictionary BomInfoCache { get; set; }
private CancellationTokenSource CancellationSwitch { get; set; }
public event EventHandler SingleCompleted;
private int bomOrder = 0;
///
/// 多线程从打开的根文档中读取BOM信息
///
/// 树型BOM列表
public void GetBomsFromDocAsync(ModelDoc2 sldDoc)
{
bomOrder = 0;
if (sldDoc == null)
{
return;
}
int drawingType = sldDoc.GetType();
Configuration activeConfiguration = sldDoc.GetActiveConfiguration() as Configuration;
if (activeConfiguration == null)
{
return;
}
CustomPropertyUtil.ClearAllCustomProperties(sldDoc);
Component2 rootComponent = activeConfiguration.GetRootComponent3(false);
string path = rootComponent.GetPathName();
BomInfo bomInfo = GetBomInfoFromDoc(rootComponent);
PdmBom bom = ConcatCacheBom(bomInfo, 0, null, rootComponent);
// ConcatBom 可能会返回null,说明这是个模拟件
if (bom == null)
{
return;
}
BomInfoCache[rootComponent.GetPathName()] = bomInfo;
CacheList.Enqueue(bom);
TreeList.Enqueue(bom);
SingleCompleted?.Invoke(this, bom);
bom.children = new ObservableCollection();
// 这里放个1,多线程说不准,就扣的快了
CountdownEvent counter = new CountdownEvent(1);
// counter.Add 要在每个子任务前执行,不能放到子任务中进行!!!
// 防止任务数太少,来不及增加计数导致直接Wait结束
counter.TryAddCount();
factory.StartNew(() =>
{
GetChildrenBomAsync(bom, rootComponent, 0, bom.children, counter);
});
counter.Wait();
counter.Dispose();
}
///
/// 多线程递归获取子BOM
///
///
private void GetChildrenBomAsync(PdmBom parent,
Component2 parentComponent,
int level,
Collection children,
CountdownEvent counter)
{
try
{
if (parentComponent == null)
{
parent.modules = new ObservableCollection();
return;
}
object[] childrenComponents = parentComponent.GetChildren();
if (childrenComponents == null)
{
parent.modules = new ObservableCollection();
return;
}
// 计算每个子料数量的缓存
Dictionary numCache = new Dictionary();
List modules = new List();
int order = -1;
foreach (object child in childrenComponents)
{
Component2 childComponent = child as Component2;
ModelDoc2 childDoc = childComponent.GetModelDoc2();
// 清楚格式不对的属性
CustomPropertyUtil.ClearAllCustomProperties(childDoc);
string childPath = childComponent.GetPathName();
PdmBom bom = null;
if (BomInfoCache.ContainsKey(childPath))
{
BomInfo info = BomInfoCache[childPath];
bom = ConcatCacheBom(info, level + 1, parent, childComponent);
// 就算有缓存,也要把新bom的treeId更新了,id在这里不一定唯一,tree是唯一的
bom.treeId = Guid.NewGuid().ToString();
}
else
{
BomInfo info = GetBomInfoFromDoc(childComponent);
if (info == null)
{
// 可能会返回null,说明这是个模拟件,直接跳过
continue;
}
BomInfoCache[childPath] = info;
bom = ConcatCacheBom(info, level + 1, parent, childComponent);
}
if (!bom.lost)
{
// // 如果bom没有丢失,处理子料
if (bom.drawingType == (int)swDocumentTypes_e.swDocASSEMBLY)
{
bom.children = new ObservableCollection();
counter.TryAddCount();
factory.StartNew(() =>
{
GetChildrenBomAsync(bom, childComponent, bom.level, bom.children, counter);
});
}
else
{
bom.modules = new ObservableCollection();
}
}
// 列表缓存
bom.order = ++order;
CacheList.Enqueue(bom);
modules.Add(bom);
SingleCompleted?.Invoke(this, bom);
// 丢没丢都要处理数量
if (numCache.ContainsKey(bom.name))
{
numCache[bom.name].quantity++;
}
else
{
numCache[bom.name] = bom;
children.Add(bom);
}
}
if (modules != null && modules.Count > 0)
{
parent.modules = new ObservableCollection(modules.OrderBy(e => e.name).ToList());
return;
}
parent.modules = new ObservableCollection();
}
finally
{
counter.Signal();
if (level == 0) counter.Signal();
}
}
public List Refresh(SldWorks swApp, ModelDoc2 doc)
{
if (swApp == null || doc == null)
{
return null;
}
CacheList = new ConcurrentQueue();
TreeList = new ConcurrentQueue();
BomInfoCache = new ConcurrentDictionary();
GetBomsFromDocAsync(doc);
return TreeList.OrderBy(e => e.name).ToList(); ;
}
///
/// 从WEB获取与Component2对应的数据库中的物料信息
///
///
///
private static BomInfo GetBomInfoFromDoc(Component2 component)
{
ModelDoc2 doc = component.GetModelDoc2();
// 直接用文件名,以免 SolidWorks 因为有多个相同文件而把 Name2 加了 -N 的后缀名
string childPath = component.GetPathName();
string childName = Path.GetFileNameWithoutExtension(childPath);
if (ModelUtil.Is_Mn(childName))
{
// 如果是个模拟件,直接跳过了
return null;
}
BomInfo bomInfo;
// id先用uuid填充
if (doc == null || string.IsNullOrEmpty(childPath) || !File.Exists(childPath))
{
bomInfo = new BomInfo
{
id = Guid.NewGuid().ToString(),
doc = doc,
lost = true,
suppressed = component.IsSuppressed(),
lightWeight = (component.GetSuppression2() == (int)swComponentSuppressionState_e.swComponentLightweight),
};
return bomInfo;
}
int drawingType = doc.GetType();
bomInfo = new BomInfo
{
id = Guid.NewGuid().ToString(),
doc = doc,
drawingType = drawingType,
properties = CustomPropertyUtil.GetCustomProperties(doc, true),
d3FilePath = childPath,
};
return bomInfo;
}
///
/// 拼接WEB中BomInfo信息和本地图纸中的Pdmbom信息
///
///
///
///
///
private static PdmBom ConcatCacheBom(BomInfo info, int level, PdmBom parent, Component2 component)
{
if (info == null) return null;
//if (component.IsHidden(true))
//{
// info.isHidden = true;
//}
PdmBom bom = new PdmBom
{
BomInfo = info,
treeId = info.id,
level = level,
quantity = 1,
parent = parent,
component = component,
isHidden = component.IsHidden(true)
};
// 封装Bom信息
bom.Init();
return bom;
}
}
}