using System; using System.Collections.Generic; using System.Data; using System.Data.OleDb; using System.Diagnostics; using System.IO; using System.Linq; using System.Reflection; using System.Text; using Autodesk.Revit.DB; using Autodesk.Revit.DB.Architecture; using Autodesk.Revit.UI; using CommunityToolkit.Mvvm.ComponentModel; using CommunityToolkit.Mvvm.Input; using Microsoft.Win32; using Nice3point.Revit.Toolkit.External.Handlers; namespace GeologyToolkit { public partial class CreatorViewModel : ObservableObject { const string VbACE = "Provider=Microsoft.ACE.OLEDB.12.0;Data Source="; private readonly ActionEventHandler action; [ObservableProperty] [NotifyCanExecuteChangedFor(nameof(CreateGeologyCommand))] string filePath; [ObservableProperty] bool isCreateSurface; bool CanCreate => FilePath != null && File.Exists(FilePath) && FilePath.EndsWith("mdb"); //const string JET = "Provider=Microsoft.JET.OLEDB.4.0;Data Source="; public CreatorViewModel() { action = new ActionEventHandler(); } /// /// 计算图层在在所有钻孔中出现的次数,单个钻孔,一类土层只计算一次 /// /// /// private Dictionary> AppearCount(List boreholes) { var layerClasses = LayersClassify(boreholes); var keyValues = new Dictionary>(); foreach (var item in layerClasses) { var currentCount = 0; var soilLayers = new List(); foreach (var borehole in boreholes) { var layers = borehole.SoilLayers.Where(l => l.MaterialCode == item.MaterialCode); if (layers.Count() > 0) { soilLayers.AddRange(layers); currentCount += 1; break; } } keyValues.Add(currentCount, soilLayers); } return keyValues; } /// /// 创建DirectShape /// /// /// private static void CreateDirectShape(Document doc, Borehole borehole) { var layers = borehole.SoilLayers; //var topElev = new XYZ(borehole.X, borehole.Y, borehole.Elev) / 304.8 * 1000; var solids = new List(); var radius = 1000.0; var lib = DirectShapeLibrary.GetDirectShapeLibrary(doc); var options = new SolidOptions(ElementId.InvalidElementId, ElementId.InvalidElementId); foreach (var layer in layers) { var curves = new List(); var curves1 = new List(); var topElev = new XYZ(borehole.X, borehole.Y, layer.TopElev) / 0.3048; var bottomElev = new XYZ(borehole.X, borehole.Y, layer.BottomElev) / 0.3048; Curve curve = Arc.Create(topElev, radius / 304.8, 0, Math.PI, XYZ.BasisX, XYZ.BasisY); Curve curve1 = Arc.Create(topElev, radius / 304.8, Math.PI, Math.PI * 2, XYZ.BasisX, XYZ.BasisY); //var bottomElev = topElev - XYZ.BasisZ * layer.Thickness / 0.3048; Curve curve2 = Arc.Create(bottomElev, radius / 304.8, 0, Math.PI, XYZ.BasisX, XYZ.BasisY); Curve curve3 = Arc.Create(bottomElev, radius / 304.8, Math.PI, Math.PI * 2, XYZ.BasisX, XYZ.BasisY); curves.Add(curve); curves.Add(curve1); curves1.Add(curve2); curves1.Add(curve3); var loop = CurveLoop.Create(curves); var loop1 = CurveLoop.Create(curves1); var cylinder = GeometryCreationUtilities.CreateBlendGeometry(loop, loop1, null); var shapeTypes = new FilteredElementCollector(doc) .OfClass(typeof(DirectShapeType)) .OfCategory(BuiltInCategory.OST_GenericModel) .WhereElementIsElementType(); var elems = shapeTypes.Where(t => t.Name == layer.Name); var directShapeType = elems.Count() == 0 ? DirectShapeType.Create(doc, layer.Name, new ElementId(BuiltInCategory.OST_GenericModel)) : elems.FirstOrDefault() as DirectShapeType; directShapeType.SetShape(new List { cylinder }); lib.AddDefinitionType("borehole", directShapeType.Id); var cateId = Category.GetCategory(doc, BuiltInCategory.OST_Mass).Id; var ds = DirectShape.CreateElementInstance( doc, directShapeType.Id, cateId, "borehole", Transform.Identity ); ds.SetTypeId(directShapeType.Id); //ds.ApplicationId = "Application id"; //ds.ApplicationDataId = "Geometry object id"; ds.SetShape(new GeometryObject[] { cylinder }); ds.SetName(layer.Name); //topElev = bottomElev; } } [RelayCommand] void SelectMDBFile() { var openFileDialog = new OpenFileDialog() { Title = "请选择地层数据库", Filter = "地层数据库(*.mdb)|*.mdb", }; if (openFileDialog.ShowDialog() == true) { FilePath = openFileDialog.FileName; } } [RelayCommand(CanExecute = nameof(CanCreate))] void CreateGeology() { action.Raise( uiapp => { var doc = uiapp.ActiveUIDocument.Document; List boreholes = null; boreholes = ProcessMdb(FilePath); //doc.Invoke(ts => //{ // foreach (var borehole in boreholes) // { // CreateSolid(doc, borehole); // } //}, "建立钻孔"); //doc.Invoke(ts => //{ // CreateSurfaceDistinct(uidoc, GetFamily(doc), boreholes); //}, "创建钻孔和地层面"); using var ts = new Transaction(doc, "创建钻孔"); ts.Start(); var family = GetFamily(doc); foreach (var borehole in boreholes) { var ids = CreateInstances(doc, family, borehole).Select(ins => ins.Id).ToList(); //UiDocument.ShowElements(ids); } #region 创建地层表面 if (IsCreateSurface) { var layerClasses = LayersClassify(boreholes); //var sb = new StringBuilder(); //for (var i = 0; i < layerClasses.Count; i++) //{ // var layer = layerClasses[i]; // sb.Append( // (i + 1).ToString() + // " " + // layer.MaterialCode + // layer.Name + // layer.DegreeofWeathering + // "\n\r"); //} //Debug.Write(sb.ToString()); foreach (var layerClass in layerClasses) { var points = new List(); foreach (var hole in boreholes) { var layers = hole.SoilLayers .Where(l => l.MaterialCode == layerClass.MaterialCode); var p = new XYZ(hole.X, hole.Y, 0) / .3048; if (layers.Count() == 0) { var elev = 100000.0; SoilLayer soilLayer = null; foreach (var layer in hole.SoilLayers) { //找到距离默认类别layerClass深度最接近的层 var temp = Math.Abs(layer.BottomElev - layerClass.BottomElev); if (temp < elev) { elev = temp; soilLayer = layer; } } p += XYZ.BasisZ * soilLayer.BottomElev / .3048; } else { p += XYZ.BasisZ * layers.First().BottomElev / .3048; } points.Add(p); } var surface = CreateTopoGraphySurface(doc, layerClass.MaterialCode, points); } } #endregion ts.Commit(); }); } /// /// 创建钻孔实例 /// /// /// /// /// private List CreateInstances(Document doc, Family family, Borehole borehole) { var layers = borehole.SoilLayers; //var topElev = new XYZ(borehole.X, borehole.Y, borehole.Elev) / 0.3048; var solids = new List(); var radius = 500 / 304.8; var familyInstances = new List(); var cateId = Category.GetCategory(doc, BuiltInCategory.OST_Mass).Id; var lib = DirectShapeLibrary.GetDirectShapeLibrary(doc); var options = new SolidOptions(ElementId.InvalidElementId, ElementId.InvalidElementId); foreach (var layer in layers) { var symbols = family.GetFamilySymbolIds().Select(id => doc.GetElement(id) as FamilySymbol); FamilySymbol symbol = null; foreach (var sym in symbols) { if (sym.Name == layer.Name) { symbol = sym; break; } } if (symbol == null) { var sym = symbols.FirstOrDefault(); symbol = sym.Duplicate(layer.Name) as FamilySymbol; } if (!symbol.IsActive) { symbol.Activate(); } //var bottomElev = topElev - XYZ.BasisZ * layer.Thickness / 0.3048; //土层顶底标高 var topElev = new XYZ(borehole.X, borehole.Y, layer.TopElev) / 0.3048; var bottomElev = new XYZ(borehole.X, borehole.Y, layer.BottomElev) / 0.3048; var ins = AdaptiveComponentInstanceUtils.CreateAdaptiveComponentInstance(doc, symbol); layer.RvInstance = ins; familyInstances.Add(ins); //自适应点 var placePointIds = AdaptiveComponentInstanceUtils.GetInstancePlacementPointElementRefIds(ins); var point = doc.GetElement(placePointIds[0]) as ReferencePoint; var point1 = doc.GetElement(placePointIds[1]) as ReferencePoint; point.Position = topElev; point1.Position = bottomElev; doc.Regenerate(); //topElev = bottomElev; //材质 ElementId materialId = null; var name = $"{layer.MaterialCode}-{layer.DegreeofWeathering}{layer.Name}"; var x = name.Split('-'); var r = Convert.ToByte(Convert.ToInt16(x[0]) * 6); var g = Convert.ToByte(Convert.ToInt16(x[1]) * 30); var b = Convert.ToByte(Convert.ToInt16(x[2]) * 60); var color = new Color(r, g, b); var materials = new FilteredElementCollector(doc).OfClass(typeof(Material)).Where(m => m.Name == name); if (materials.Count() > 0) { materialId = materials.FirstOrDefault().Id; } else { materialId = Material.Create(doc, name); var material = doc.GetElement(materialId) as Material; material.Color = color; } //修改参数值 try { ins.LookupParameter("开工日期").Set(borehole.StartWorkDate); ins.LookupParameter("竣工日期").Set(borehole.EndWorkDate); ins.LookupParameter("地层编号").Set(layer.SerialNum.ToString()); ins.LookupParameter("钻孔编号").Set(borehole.BoreholeNum); ins.LookupParameter("钻孔坐标").Set(borehole.Coord); ins.LookupParameter("地层厚度").Set(layer.Thickness.ToString()); ins.LookupParameter("孔口标高").Set(borehole.Elev.ToString()); ins.LookupParameter("勘探深度").Set(borehole.Depth); ins.LookupParameter("岩石风化程度").Set(layer.DegreeofWeathering); ins.LookupParameter("类型").Set(borehole.BoreholeType); ins.LookupParameter("颜色").Set(layer.Color); ins.LookupParameter("其他描述信息").Set(layer.OtherDescription); ins.LookupParameter("初见水位埋深").Set(borehole.MeetWaterLine); ins.LookupParameter("初见水位观测日期").Set(borehole.MeetWaterLineDate); ins.LookupParameter("稳定水位埋深").Set(borehole.StableWaterLine); ins.LookupParameter("稳定水位观测日期").Set(borehole.StableWaterLineDate); ins.Symbol.LookupParameter("钻孔半径").Set(radius); ins.LookupParameter("材质").Set(materialId); } catch (Exception) { } } return familyInstances; } /// /// 通过去钻孔土层去重后建立钻孔及曲面 /// /// /// /// private void CreateSurfaceDistinct(Document doc) { var totalLayers = new List(); var gros = totalLayers.GroupBy(layer => layer.BoreholeNum).Select(g => g.Count() >= 2); //TaskDialog.Show("同一个钻孔存在同类型的土层", sb.ToString()); var groups = totalLayers.GroupBy(layer => layer.MaterialCode); foreach (var group in groups) { if (group.Count() <= 2) { continue; } var points = new List(); foreach (var layer in group) { var p = new XYZ(layer.Ower.X, layer.Ower.Y, layer.BottomElev) / 0.3048; points.Add(p); } CreateTopoGraphySurface(doc, group.Key, points); } } /// /// 创建地形表面 /// /// /// 材质名称 /// 点集 private TopographySurface CreateTopoGraphySurface(Document document, string name, List points) { var materialId = new FilteredElementCollector(document) .OfClass(typeof(Material)) .Where(m => m.Name.Contains(name)) .FirstOrDefault()? .Id; if (materialId == null) { materialId = Material.Create(document, name); } var surface = TopographySurface.Create(document, points); surface.MaterialId = materialId; return surface; } /// /// 获取土层族 /// /// private static Family GetFamily(Document doc) { var dir = Path.GetDirectoryName(Assembly.GetExecutingAssembly().Location); var famdoc = doc.LoadFamily($@"{dir}\钻孔土层.rfa", new LoadFamilyOptions(), out var family); if (family == null) { family = new FilteredElementCollector(doc) .OfClass(typeof(Family)) .Cast() .Where(fam => fam.Name == "钻孔土层") .FirstOrDefault(); } return family; } /// /// 找到当前地质中所有土层分类的默认实例 /// /// /// private List LayersClassify(List boreholes) { var layerClasses = new List(); foreach (var borehole in boreholes) { foreach (var item in borehole.SoilLayers) { var count = layerClasses.Where(l => l.MaterialCode == item.MaterialCode).Count(); if (count == 0) { layerClasses.Add(item); } } } return layerClasses; } /// /// 数据转实例 /// /// /// private List ProcessMdb(string path) { var boreholes = new List(); try { using var connection = new OleDbConnection($"{VbACE}{path};"); //using (OleDbConnection connection = new OleDbConnection(string.Format("Provider=Microsoft.Jet.OLEDB.4.0; Data Source={0};", path))) connection.Open(); var allTables = new DataSet(); var schema = connection.GetOleDbSchemaTable( OleDbSchemaGuid.Tables, new object[] { null, null, null, "TABLE" } ); DataTable boreHoleTable = null; DataTable soilLayerTable = null; DataTable waterLineTable = null; foreach (DataRow row in schema.Rows) { var table = new DataTable(row["TABLE_NAME"].ToString()); if (table.TableName == "z_ZuanKong") { boreHoleTable = table; } if (table.TableName == "z_g_TuCeng") { soilLayerTable = table; } if (table.TableName == "z_g_ShuiWei") { waterLineTable = table; } //if (table.TableName == "g_STuCeng") //{ // soilLayerClasses = table; //} } if (null == boreHoleTable || null == soilLayerTable) { return null; } var boreHoleAdapter = new OleDbDataAdapter($"SELECT * FROM [{boreHoleTable.TableName}]", connection); boreHoleAdapter.Fill(boreHoleTable); var soilLayerAdapter = new OleDbDataAdapter($"SELECT * FROM [{soilLayerTable.TableName}]", connection); soilLayerAdapter.Fill(soilLayerTable); var waterLineAdapter = new OleDbDataAdapter($"SELECT * FROM [{waterLineTable.TableName}]", connection); waterLineAdapter.Fill(waterLineTable); //OleDbDataAdapter layerAdapter = new OleDbDataAdapter($"SELECT * FROM [{soilLayerClasses.TableName}]", connection); //layerAdapter.Fill(soilLayerClasses); //int zkbhIndex = boreHoleTable.Columns.IndexOf(boreHoleTable.Columns["ZKBH"]);//钻孔编号的索引 //int zklxIndex = boreHoleTable.Columns.IndexOf(boreHoleTable.Columns["ZKLX"]);//钻孔类型的索引 //int zkxIndex = boreHoleTable.Columns.IndexOf(boreHoleTable.Columns["ZKX"]);//钻孔X坐标的索引 //int zkyIndex = boreHoleTable.Columns.IndexOf(boreHoleTable.Columns["ZKY"]);//钻孔Y坐标的索引 foreach (DataRow drillRow in boreHoleTable.Rows) { var borehole = new Borehole { BoreholeNum = $"{drillRow["ZKBH"]}", X = Convert.ToDouble(drillRow["ZKX"]), Y = Convert.ToDouble(drillRow["ZKY"]), Elev = Math.Round(Convert.ToDouble(drillRow["ZKBG"]), 3), StartWorkDate = $"{drillRow["ZKKSRQ"]}", EndWorkDate = $"{drillRow["ZKZZRQ"]}", Depth = $"{drillRow["ZKSD"]}", BoreholeType = $"{drillRow["ZKLX"]}" }; var zkbh1Index = boreHoleTable.Columns.IndexOf(boreHoleTable.Columns["ZKBH"]); //钻孔编号的索引 var tempLayers = new List(); foreach (DataRow layerRow in soilLayerTable.Rows) { var num = layerRow["ZKBH"].ToString(); if (borehole.BoreholeNum == num) { var soilLayer = new SoilLayer { Ower = borehole, BoreholeNum = $"{layerRow["ZKBH"]}", Name = $"{layerRow["TCMC"]}", SerialNum = Convert.ToInt16(layerRow["TCXH"]), Thickness = Convert.ToDouble(layerRow["TCHD"].ToString()), Color = $"{layerRow["TCYS"]}", DegreeofWeathering = $"{layerRow["TCFHCD"]}", OtherDescription = $"{layerRow["TCMS"]}", MaterialCode = $"{layerRow["TCZCBH"]}-{layerRow["TCYCBH"]}-{layerRow["TCCYCBH"]}" }; tempLayers.Add(soilLayer); } } ; foreach (DataRow waterlineRow in waterLineTable.Rows) { var num = waterlineRow["ZKBH"].ToString(); if (borehole.BoreholeNum == num) { var num1 = waterlineRow["SWLX"].ToString(); if (num1 == "0") { borehole.MeetWaterLine = $"{waterlineRow["SWSD"]}"; borehole.MeetWaterLineDate = $"{waterlineRow["SWCSRQ"]}"; } else if (num1 == "1") { borehole.StableWaterLine = $"{waterlineRow["SWSD"]}"; borehole.StableWaterLineDate = $"{waterlineRow["SWCSRQ"]}"; } } } var orderLayers = tempLayers.OrderBy(x => x.SerialNum).ToList(); borehole.SoilLayers = orderLayers; boreholes.Add(borehole); //WriteTextForDataTable(newDataTable); } //foreach (DataRow layerClass in soilLayerClasses.Rows) //{ // var layer = new SoilLayer() // { // MaterialCode = $"{layerClass["TCZCBH"]}-{layerClass["TCYCBH"]}-{layerClass["TCCYCBH"]}" // }; // layerClasses.Add(layer); //} connection.Close(); } catch (Exception) { throw; } return boreholes; } private void ShowInstances(UIDocument uidoc, List familyInstances) { uidoc.ShowElements(familyInstances.Select(ins => ins.Id).ToList()); } private static void WriteTextForDataTable(DataTable newDataTable) { var tableContents = new StringBuilder(); var rowContents = new StringBuilder(); for (var rowIndex = 0; rowIndex < newDataTable.Rows.Count; rowIndex++) { for (var itemIndex = 0; itemIndex < newDataTable.Rows[rowIndex].ItemArray.Length; itemIndex++) { rowContents.Append(newDataTable.Rows[rowIndex].ItemArray[itemIndex]); rowContents.Append(","); } tableContents.Append(rowContents); tableContents.Append(Environment.NewLine); rowContents.Length = 0; } TaskDialog.Show($"{newDataTable.TableName}", tableContents.ToString()); } } }