From b7414f697ce0b71b7f83cd62666e957e60e01fdc Mon Sep 17 00:00:00 2001 From: kike-garbo Date: Thu, 19 Dec 2024 15:31:13 +0100 Subject: [PATCH] Improvements on Previews. - Now is faster. - Now dependent elements are drawn in wire-frame. --- .../Types/GeometricElement.cs | 309 ++++++++++++------ .../Convert/Display/PreviewConverter.cs | 8 +- 2 files changed, 219 insertions(+), 98 deletions(-) diff --git a/src/RhinoInside.Revit.GH/Types/GeometricElement.cs b/src/RhinoInside.Revit.GH/Types/GeometricElement.cs index 3e2858f66..41a3ca1b4 100644 --- a/src/RhinoInside.Revit.GH/Types/GeometricElement.cs +++ b/src/RhinoInside.Revit.GH/Types/GeometricElement.cs @@ -5,6 +5,7 @@ using Grasshopper.Kernel; using Grasshopper.Kernel.Types; using Rhino; +using Rhino.Display; using Rhino.DocObjects; using Rhino.Geometry; using ARDB = Autodesk.Revit.DB; @@ -20,7 +21,6 @@ namespace RhinoInside.Revit.GH.Types using Convert.Display; using Convert.DocObjects; using Convert.Geometry; - using Convert.System.Drawing; using External.DB; using External.DB.Extensions; @@ -85,6 +85,46 @@ public override BoundingBox GetBoundingBox(Transform xform) } #region Preview + internal static void BuildPreview + ( + ARDB.Element element, MeshingParameters meshingParameters, ARDB.ViewDetailLevel detailLevel, + out ARDB.View view, List materials, List meshes, List wires + ) + { + bool voidGeometry = element is ARDB.GenericForm form && !form.IsSolid; + + using + ( + var options = element.ViewSpecific ? + new ARDB.Options() { View = element.Document.GetElement(element.OwnerViewId) as ARDB.View, IncludeNonVisibleObjects = voidGeometry } : + new ARDB.Options() { DetailLevel = detailLevel == ARDB.ViewDetailLevel.Undefined ? ARDB.ViewDetailLevel.Medium : detailLevel, IncludeNonVisibleObjects = voidGeometry } + ) + { + view = options.View; + using (var geometry = element?.GetGeometry(options)) + { + if (geometry is null) + { + materials = null; + meshes = null; + wires = null; + } + else + { + wires.AddRange(geometry.GetPreviewWires().Where(x => x is object)); + if (!voidGeometry) + { + var categoryMaterial = element.Category?.Material; + var elementMaterial = geometry.MaterialElement ?? categoryMaterial; + + meshes?.AddRange(geometry.GetPreviewMeshes(element.Document, meshingParameters)); + materials?.AddRange(geometry.GetPreviewMaterials(element.Document, elementMaterial)); + } + } + } + } + } + internal static void BuildPreview ( ARDB.Element element, MeshingParameters meshingParameters, ARDB.ViewDetailLevel detailLevel, @@ -168,44 +208,109 @@ class Preview : IDisposable readonly BoundingBox clippingBox; public readonly MeshingParameters MeshingParameters; public Rhino.Display.DisplayMaterial[] materials; - static readonly Rhino.Display.DisplayMaterial[] empty_materials = Array.Empty(); public Mesh[] meshes; - static readonly Mesh[] empty_meshes = Array.Empty(); public Curve[] wires; - static readonly Curve[] empty_wires = Array.Empty(); - + public Curve[] highlights; static List previewsQueue; void Build() { if (!geometricElement.IsValid || !clippingBox.IsValid) { - materials = empty_materials; - meshes = empty_meshes; - wires = empty_wires; + materials = Array.Empty(); + meshes = Array.Empty(); + wires = Array.Empty(); + highlights = Array.Empty(); } - else if (meshes is null && wires is null && materials is null) + else if (meshes is null && wires is null && materials is null && highlights is null) { var element = geometricElement.Document.GetElement(geometricElement.Id); if (element is null) return; - BuildPreview(element, MeshingParameters, ARDB.ViewDetailLevel.Undefined, out var materialElements, out meshes, out wires); + var elementMaterials = new List(); + var elementMeshes = new List(); + var elementWires = new List(); + var elementHighlight = new List(); + BuildPreview(element, MeshingParameters, ARDB.ViewDetailLevel.Undefined, out var elementView, default, elementMeshes, elementWires); + + //if (element.Location is ARDB.LocationCurve elementCurve) + // elementHighlight.Add(elementCurve.Curve.ToCurve()); + + // Extract dependents preview + { + var dependents = new List(); + switch (element) + { + case ARDB.FamilyInstance instance: + dependents.AddRange(instance.GetSubComponentIds()); + break; + + case ARDB.Wall wall: + if (wall.IsStackedWall) dependents.AddRange(wall.GetStackedWallMemberIds()); + if (wall.CurtainGrid is ARDB.CurtainGrid grid) dependents.AddRange(grid.GetMullionIds().Concat(grid.GetPanelIds())); + break; + + case ARDB.BeamSystem beamSystem: + dependents.AddRange(beamSystem.GetBeamIds()); + break; + + case ARDB.Architecture.Railing railing: + if (railing.TopRail.IsValid()) dependents.Add(railing.TopRail); + dependents.AddRange(railing.GetHandRails()); + break; + + default: + if (elementWires.Count == 0 && elementMeshes.Count == 0 && element.get_BoundingBox(elementView) is ARDB.BoundingBoxXYZ) + dependents.AddRange(element.GetDependentElements(CompoundElementFilter.ElementHasBoundingBoxFilter)); + break; + } - // Combine meshes of same material for display performance - if (meshes is object && materialElements is object) + //if (element is ARDB.HostObject hostObject) + // dependents.AddRange(hostObject.FindInserts(false, false, false, false)); + + foreach (var dependent in dependents.Select(element.Document.GetElement)) + BuildPreview(dependent, MeshingParameters, ARDB.ViewDetailLevel.Undefined, out var _, null, null, elementHighlight); + } + + // Optimize for display { - var outMesh = new Mesh(); - var dictionary = PreviewConverter.ZipByMaterial(materialElements, meshes, outMesh); - if (outMesh.Faces.Count > 0) + wires = elementWires.ToArray(); + highlights = elementHighlight.ToArray(); + + foreach (var elementMesh in elementMeshes) + elementMesh.Normals.ComputeNormals(); + + // Combine meshes of same material for display performance + if (elementMeshes.Count > 0 && elementMeshes.Count == elementMaterials.Count) { - materials = dictionary.Keys.Select(DisplayMaterialConverter.ToDisplayMaterial).Concat(Enumerable.Repeat(new Rhino.Display.DisplayMaterial(), 1)).ToArray(); - meshes = dictionary.Values.Concat(Enumerable.Repeat(outMesh, 1)).ToArray(); + var outMesh = new Mesh(); + var dictionary = PreviewConverter.ZipByMaterial(elementMaterials, elementMeshes, outMesh); + if (outMesh.Faces.Count > 0) + { + var pairs = dictionary;//.OrderBy(x => x.Key.Transparency).ToList(); + materials = pairs.Select(x => DisplayMaterialConverter.ToDisplayMaterial(x.Key)).Concat(Enumerable.Repeat(new DisplayMaterial(), 1)).ToArray(); + meshes = pairs.Select(x => x.Value).Concat(Enumerable.Repeat(outMesh, 1)).ToArray(); + } + else + { + var pairs = dictionary;//.OrderBy(x => x.Key.Transparency).ToList(); + materials = pairs.Select(x => DisplayMaterialConverter.ToDisplayMaterial(x.Key)).ToArray(); + meshes = pairs.Select(x => x.Value).ToArray(); + } } else { - materials = dictionary.Keys.Select(DisplayMaterialConverter.ToDisplayMaterial).ToArray(); - meshes = dictionary.Values.ToArray(); + materials = Array.Empty(); + if (elementMeshes.Count > 1) + { + var combined = new Mesh(); + foreach (var mesh in elementMeshes) + combined.Append(mesh); + + meshes = new Mesh[] { combined }; + } + else meshes = elementMeshes.ToArray(); } } } @@ -300,6 +405,14 @@ void IDisposable.Dispose() wires = null; } + + if (highlights is object) + { + foreach (var highlight in highlights) + highlight.Dispose(); + + highlights = null; + } } } @@ -334,6 +447,8 @@ public Mesh[] TryGetPreviewMeshes(MeshingParameters parameters) public Mesh[] TryGetPreviewMeshes() => GeometryPreview.meshes; public Curve[] TryGetPreviewWires() => GeometryPreview.wires; + + public Curve[] TryGetPreviewHighlights() => GeometryPreview.highlights; #endregion #region IGH_PreviewData @@ -347,46 +462,55 @@ protected override void DrawViewportMeshes(GH_PreviewMeshArgs args) return; var material = args.Material; - var element = Value; - if (element is null) - { - const int factor = 3; - - // Erased element - material = new Rhino.Display.DisplayMaterial(material) - { - Diffuse = System.Drawing.Color.FromArgb(20, 20, 20), - Emission = System.Drawing.Color.FromArgb(material.Emission.R / factor, material.Emission.G / factor, material.Emission.B / factor), - Shine = 0.0, - }; - } - else if (!element.Pinned) - { - if (args.Pipeline.DisplayPipelineAttributes.ShadingEnabled) - { - // Unpinned element - if (args.Pipeline.DisplayPipelineAttributes.UseAssignedObjectMaterial) - { - var materials = TryGetPreviewMaterials(); - - for (int m = 0; m < meshes.Length; ++m) - args.Pipeline.DrawMeshShaded(meshes[m], materials[m]); - - return; - } - else - { - material = new Rhino.Display.DisplayMaterial(material) - { - Diffuse = element.Category?.LineColor.ToColor() ?? System.Drawing.Color.White, - Transparency = 0.0 - }; - - if (material.Diffuse == System.Drawing.Color.Black) - material.Diffuse = System.Drawing.Color.White; - } - } - } + //var element = Value; + //if (element is null) + //{ + // const int factor = 3; + + // // Erased element + // material = new Rhino.Display.DisplayMaterial(material) + // { + // Diffuse = System.Drawing.Color.FromArgb(20, 20, 20), + // Emission = System.Drawing.Color.FromArgb(material.Emission.R / factor, material.Emission.G / factor, material.Emission.B / factor), + // Shine = 0.0, + // }; + //} + //else if (!element.Pinned) + //{ + // if (args.Pipeline.DisplayPipelineAttributes.ShadingEnabled) + // { + // // Unpinned element + // if (args.Pipeline.DisplayPipelineAttributes.UseAssignedObjectMaterial) + // { + // var materials = TryGetPreviewMaterials(); + + // for (int m = 0; m < meshes.Length; ++m) + // args.Pipeline.DrawMeshShaded(meshes[m], materials[m]); + + // return; + // } + // else + // { + // material = new Rhino.Display.DisplayMaterial(material) + // { + // Diffuse = element.Category?.LineColor.ToColor() ?? System.Drawing.Color.White, + // Transparency = 0.0 + // }; + + // if (material.Diffuse == System.Drawing.Color.Black) + // material.Diffuse = System.Drawing.Color.White; + + // var materials = TryGetPreviewMaterials(); + // for (int m = 0; m < meshes.Length; ++m) + // { + // material.Transparency = materials[m].Transparency; + // args.Pipeline.DrawMeshShaded(meshes[m], material); + // } + + // return; + // } + // } + //} foreach (var mesh in meshes) args.Pipeline.DrawMeshShaded(mesh, material); @@ -397,49 +521,46 @@ protected override void DrawViewportWires(GH_PreviewWireArgs args) if (!IsValid) return; - if (!args.Pipeline.DisplayPipelineAttributes.ShowSurfaceEdges && args.Thickness <= 1) - return; - - int thickness = 1; //args.Thickness; - + var thickness = args.Thickness * args.Pipeline.DpiScale; var color = args.Color; - var element = Value; - if (element is null) - { - // Erased element - const int factor = 3; - color = System.Drawing.Color.FromArgb(args.Color.R / factor, args.Color.G / factor, args.Color.B / factor); - } - else if (!element.Pinned) + + var drawBox = true; + var higlights = TryGetPreviewHighlights(); + if (higlights is object && higlights.Length > 0) { - // Unpinned element - if (args.Thickness <= 1 && args.Pipeline.DisplayPipelineAttributes.UseAssignedObjectMaterial) - color = System.Drawing.Color.Black; + drawBox = false; + DrawWires(args.Pipeline, higlights, System.Drawing.Color.FromArgb(100, color), thickness/*, 5.0f*/); } var wires = TryGetPreviewWires(); if (wires is object && wires.Length > 0) { - foreach (var wire in wires) - args.Pipeline.DrawCurve(wire, color, thickness); + drawBox = false; + DrawWires(args.Pipeline, wires, color, thickness); } - else + + if (drawBox) base.DrawViewportWires(args); + } + + private static void DrawWires(DisplayPipeline pipeline, IEnumerable wires, System.Drawing.Color color, float thickness, float? pattern = default) + { +#if RHINO_8 + var pen = new DisplayPen() { - var meshes = TryGetPreviewMeshes(); - if (meshes is object) - { - if (meshes.Length == 0) - { - base.DrawViewportWires(args); - } - else if (Grasshopper.CentralSettings.PreviewMeshEdges) - { - foreach (var mesh in meshes) - args.Pipeline.DrawMeshWires(mesh, color, thickness); - } - } - else base.DrawViewportWires(args); - } + Color = color, + Thickness = thickness, + ThicknessSpace = CoordinateSystem.Screen, + PatternLengthInWorldUnits = false, + }; + + if (pattern.HasValue) pen.SetPattern(new float[] { pattern.Value, pattern.Value }); + + foreach (var wire in wires) + pipeline.DrawCurve(wire, pen); +#else + foreach (var wire in wires) + pipeline.DrawCurve(wire, color, (int) Math.Round(thickness)); +#endif } #endregion @@ -911,7 +1032,7 @@ internal override ModelContent ToModelContent(IDictionary HostElement; diff --git a/src/RhinoInside.Revit/Convert/Display/PreviewConverter.cs b/src/RhinoInside.Revit/Convert/Display/PreviewConverter.cs index ec3a95872..c73221bfc 100644 --- a/src/RhinoInside.Revit/Convert/Display/PreviewConverter.cs +++ b/src/RhinoInside.Revit/Convert/Display/PreviewConverter.cs @@ -27,16 +27,16 @@ static bool SkipGeometryObject(ARDB.GeometryObject geometryObject, ARDB.Document #region GetPreviewMaterials internal static Dictionary ZipByMaterial ( - ARDB.Material[] materialElements, - Mesh[] meshes, + IList materialElements, + IList meshes, Mesh outMesh = default ) { if (materialElements is null || meshes is null) return null; - var dictionary = new Dictionary(External.DB.Extensions.ElementEqualityComparer.SameDocument); + var dictionary = new Dictionary(ElementEqualityComparer.SameDocument); - for (int index = 0; index < materialElements.Length && index < meshes.Length; ++index) + for (int index = 0; index < materialElements.Count && index < meshes.Count; ++index) { if (materialElements[index] is null) {