diff --git a/src/RhinoInside.Revit.External/Extensions/RhinoCommon.cs b/src/RhinoInside.Revit.External/Extensions/RhinoCommon.cs index 7db288561..ad01a406f 100644 --- a/src/RhinoInside.Revit.External/Extensions/RhinoCommon.cs +++ b/src/RhinoInside.Revit.External/Extensions/RhinoCommon.cs @@ -2,6 +2,7 @@ using System.Collections.Generic; using System.Linq; using Microsoft.Win32.SafeHandles; +using Rhino.Render; using RhinoInside.Revit.External.DB.Extensions; using RhinoInside.Revit.Numerical; @@ -1368,6 +1369,14 @@ public static Geometry.Rectangle3d GetFrustumRectangle(this ViewportInfo vport, namespace Rhino.DocObjects.Tables { + static class MaterialTableExtension + { + public static Material FindName(this MaterialTable table, string name) + { + return table.FirstOrDefault(x => !x.IsReference && !x.IsDeleted && string.Equals(x.Name, name, StringComparison.InvariantCultureIgnoreCase)); + } + } + static class NamedConstructionPlaneTableExtension { public static int Add(this NamedConstructionPlaneTable table, ConstructionPlane cplane) @@ -1533,6 +1542,11 @@ namespace Rhino.Render { static class RenderMaterialExtension { + public static RenderMaterial FindName(this RenderMaterialTable table, string name) + { + return table.FirstOrDefault(x => !x.IsReference() && string.Equals(x.Name, name, StringComparison.InvariantCultureIgnoreCase)); + } + #if !RHINO_8 public static RenderMaterial Find(this RenderMaterialTable table, Guid id) { diff --git a/src/RhinoInside.Revit.GH/Components/Element/Material/ByName.cs b/src/RhinoInside.Revit.GH/Components/Element/Material/ByName.cs index 70c8b3ec5..1396d8ce3 100755 --- a/src/RhinoInside.Revit.GH/Components/Element/Material/ByName.cs +++ b/src/RhinoInside.Revit.GH/Components/Element/Material/ByName.cs @@ -266,7 +266,7 @@ protected override void TrySolveInstance(IGH_DataAccess DA) if (newColor.Red != material.Color.Red || newColor.Green != material.Color.Green || newColor.Blue != material.Color.Blue) material.Color = newColor; - var newTransparency = (int) Math.Round((255 - color.A) * 100.0 / 255.0); + var newTransparency = (int) Math.Round((byte.MaxValue - color.A) / 2.55); if (material.Transparency != newTransparency) material.Transparency = newTransparency; diff --git a/src/RhinoInside.Revit.GH/Types/Datums/ProjectLocation.cs b/src/RhinoInside.Revit.GH/Types/Datums/ProjectLocation.cs index d798667a2..446e24fb3 100644 --- a/src/RhinoInside.Revit.GH/Types/Datums/ProjectLocation.cs +++ b/src/RhinoInside.Revit.GH/Types/Datums/ProjectLocation.cs @@ -74,7 +74,7 @@ protected override void DrawViewportWires(GH_PreviewWireArgs args) bool IGH_BakeAwareData.BakeGeometry(RhinoDoc doc, ObjectAttributes att, out Guid guid) => BakeElement(new Dictionary(), true, doc, att, out guid); - public bool BakeElement + public override bool BakeElement ( IDictionary idMap, bool overwrite, diff --git a/src/RhinoInside.Revit.GH/Types/GeometricElement+Bake.cs b/src/RhinoInside.Revit.GH/Types/GeometricElement+Bake.cs new file mode 100644 index 000000000..c087eb02b --- /dev/null +++ b/src/RhinoInside.Revit.GH/Types/GeometricElement+Bake.cs @@ -0,0 +1,289 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using Grasshopper.Kernel; +using Grasshopper.Kernel.Types; +using Rhino; +using Rhino.DocObjects; +using Rhino.Geometry; +using Rhino.Render; +using ARDB = Autodesk.Revit.DB; + +namespace RhinoInside.Revit.GH.Types +{ + using Convert.DocObjects; + using Convert.Geometry; + using External.DB.Extensions; + + partial class GeometricElement + { + #region IGH_BakeAwareElement + bool IGH_BakeAwareData.BakeGeometry(RhinoDoc doc, ObjectAttributes att, out Guid guid) => + BakeElement(new Dictionary(), true, doc, att, out guid); + + static System.Drawing.Color EnsureNoBlack(System.Drawing.Color value) + { + return (value.R == 0 && value.G == 0 && value.B == 0) ? System.Drawing.Color.FromArgb(value.A, 1, 1, 1) : value; + } + + static ObjectAttributes CreateObjectAttributes(IDictionary idMap, RhinoDoc doc, ARDB.Document document) + { + var context = GeometryDecoder.Context.Peek; + var attributes = new ObjectAttributes(); + + if (context.Category is ARDB.Category category) + { + if (new Category(category).BakeElement(idMap, false, doc, default, out var layerGuid)) + attributes.LayerIndex = doc.Layers.FindId(layerGuid).Index; + } + + if (context.Material is ARDB.Material material) + { + if (new Material(material).BakeElement(idMap, false, doc, default, out var materialGuid)) + attributes.RenderMaterial = doc.RenderMaterials.Find(materialGuid); + } + + return attributes; + } + + public virtual bool BakeElement + ( + IDictionary idMap, + bool overwrite, + RhinoDoc doc, + ObjectAttributes att, + out Guid guid + ) + { + // 1. Check if is already cloned + guid = Guid.Empty; + + // 3. Update if necessary + if (Value is ARDB.Element element) + { + using (var options = new ARDB.Options() { DetailLevel = ARDB.ViewDetailLevel.Fine }) + { + using (var geometry = element.GetGeometry(options)) + { + if (geometry is object) + { + using (var context = GeometryDecoder.Context.Push()) + { + context.Element = element; + context.Category = element.Category; + context.Material = element.Category?.Material; + + var location = element.Category is null || element.Category.Parent is object ? + Plane.WorldXY : + Location; + + var worldToElement = Transform.PlaneToPlane(location, Plane.WorldXY); + if (BakeGeometryElement(idMap, overwrite, doc, worldToElement, element, geometry, out var idefIndex)) + { + att = att?.Duplicate() ?? doc.CreateDefaultAttributes(); + att.Space = ActiveSpace.ModelSpace; + att.ViewportId = Guid.Empty; + att.Name = element.get_Parameter(ARDB.BuiltInParameter.ALL_MODEL_MARK)?.AsString() ?? string.Empty; + att.Url = element.get_Parameter(ARDB.BuiltInParameter.ALL_MODEL_URL)?.AsString() ?? string.Empty; + + if (Category.BakeElement(idMap, false, doc, att, out var layerGuid)) + att.LayerIndex = doc.Layers.FindId(layerGuid).Index; + + guid = doc.Objects.AddInstanceObject(idefIndex, Transform.PlaneToPlane(Plane.WorldXY, location), att); + + // We don't want geometry on the active viewport but on its own. + doc.Objects.ModifyAttributes(guid, att, quiet: true); + } + } + + if (guid != Guid.Empty) + return true; + } + } + } + } + + return false; + } + + protected internal static bool BakeGeometryElement + ( + IDictionary idMap, + bool overwrite, + RhinoDoc doc, + Transform transform, + ARDB.Element element, + ARDB.GeometryElement geometryElement, + out int index + ) + { + // 1. Check if is already cloned + if (idMap.TryGetValue(element.Id, out var guid)) + { + index = doc.InstanceDefinitions.FindId(guid).Index; + return true; + } + + var geometryElementContent = geometryElement.ToArray(); + if (geometryElementContent.Length < 1) + { + index = -1; + return false; + } + else if + ( + geometryElementContent.Length == 1 && + geometryElementContent[0] is ARDB.GeometryInstance geometryInstance && + geometryInstance.GetSymbol() is ARDB.ElementType symbol + ) + { + // Special case to simplify ARDB.FamilyInstance elements. + var instanceTransform = geometryInstance.Transform.ToTransform(); + return BakeGeometryElement(idMap, false, doc, instanceTransform * transform, symbol, geometryInstance.SymbolGeometry, out index); + } + + // Get a Unique Instance Definition name. + var idef_name = NameConverter.EscapeName(element, out var idef_description); + + // 2. Check if already exist + index = doc.InstanceDefinitions.Find(idef_name)?.Index ?? -1; + + // 3. Update if necessary + if (index < 0 || overwrite) + { + bool identity = transform.IsIdentity; + + GeometryDecoder.UpdateGraphicAttributes(geometryElement); + + var geometry = new List(geometryElementContent.Length); + var attributes = new List(geometryElementContent.Length); + + foreach (var g in geometryElementContent) + { + using (GeometryDecoder.Context.Push()) + { + GeometryDecoder.UpdateGraphicAttributes(g); + + var objectGeometry = default(GeometryBase); + switch (g) + { + case ARDB.Mesh m: if (m.NumTriangles > 0) objectGeometry = m.ToMesh(); break; + case ARDB.Solid s: if (!s.Faces.IsEmpty) objectGeometry = s.ToBrep(); break; + case ARDB.Curve c: objectGeometry = c.ToCurve(); break; + case ARDB.PolyLine p: if (p.NumberOfCoordinates > 0) objectGeometry = p.ToPolylineCurve(); break; + case ARDB.GeometryInstance i: + using (GeometryDecoder.Context.Push()) + { + if (BakeGeometryElement(idMap, false, doc, Transform.Identity, i.GetSymbol(), i.SymbolGeometry, out var idefIndex)) + objectGeometry = new InstanceReferenceGeometry(doc.InstanceDefinitions[idefIndex].Id, i.Transform.ToTransform()); + } + break; + } + + if (objectGeometry is null) continue; + if (!identity) objectGeometry.Transform(transform); + + var objectAttributes = CreateObjectAttributes(idMap, doc, element.Document); + + if (objectGeometry is Mesh mesh) + { + var context = GeometryDecoder.Context.Peek; + if (context.FaceMaterialId?.Length == 1 && context.FaceMaterialId[0].IsValid()) + { + var faceMaterial = new Material(element.Document, context.FaceMaterialId[0]); + if (faceMaterial.BakeElement(idMap, false, doc, null, out var materialId)) + { + objectAttributes.RenderMaterial = doc.RenderMaterials.Find(materialId); + objectAttributes.ColorSource = ObjectColorSource.ColorFromObject; + objectAttributes.ObjectColor = faceMaterial.ObjectColor; + } + } + } + else if (objectGeometry is Brep brep) + { + // In case objectGeometry is a Brep and has different materials per face. + var context = GeometryDecoder.Context.Peek; + if (context.FaceMaterialId?.Length > 0) + { + bool hasPerFaceMaterials = false; + { + for (int f = 1; f < context.FaceMaterialId.Length && !hasPerFaceMaterials; ++f) + hasPerFaceMaterials |= context.FaceMaterialId[f] != context.FaceMaterialId[f - 1]; + } + + if (hasPerFaceMaterials) + { + var layer = doc.Layers[objectAttributes.LayerIndex]; + + if (objectAttributes.MaterialIndex < 0) objectAttributes.MaterialIndex = doc.Materials.Add(); + var objectMaterial = doc.Materials[objectAttributes.MaterialIndex]; + if (layer.RenderMaterial is RenderMaterial layerMaterial) + { + layerMaterial.SimulateMaterial(ref objectMaterial, RenderTexture.TextureGeneration.Allow); + objectMaterial.RenderMaterialInstanceId = layerMaterial.Id; + } + else objectMaterial.RenderMaterialInstanceId = default; + objectMaterial.ClearMaterialChannels(); + + foreach (var face in brep.Faces) + { + var faceMaterialId = context.FaceMaterialId[face.SurfaceIndex]; + if (faceMaterialId != (context.Material?.Id ?? ARDB.ElementId.InvalidElementId)) + { + var faceMaterial = new Material(element.Document, faceMaterialId); + if (faceMaterial.BakeSharedMaterial(idMap, false, doc, out var materialGuid)) + { + face.MaterialChannelIndex = objectMaterial.MaterialChannelIndexFromId(materialGuid, true); + } + } + else + { + var materialIndex = layer.RenderMaterialIndex; + if (doc.Materials[materialIndex] is Rhino.DocObjects.Material material) + { + face.MaterialChannelIndex = objectMaterial.MaterialChannelIndexFromId(material.Id, true); + face.PerFaceColor = EnsureNoBlack(material.DiffuseColor); + } + else + { + face.ClearMaterialChannelIndex(); + } + } + } + + doc.Materials.Modify(objectMaterial, objectAttributes.MaterialIndex, quiet: true); + objectAttributes.MaterialSource = ObjectMaterialSource.MaterialFromObject; + } + else if (context.FaceMaterialId[0].IsValid()) + { + var objectMaterial = new Material(element.Document, context.FaceMaterialId[0]); + if (objectMaterial.BakeElement(idMap, false, doc, null, out var materialId)) + { + objectAttributes.RenderMaterial = doc.RenderMaterials.Find(materialId); + objectAttributes.ColorSource = ObjectColorSource.ColorFromObject; + objectAttributes.ObjectColor = objectMaterial.ObjectColor; + } + } + + // If we don't have per-face materials let's try to convert it to an extrusion. + if (!hasPerFaceMaterials && brep.TryGetExtrusion(out var extrusion) is true) + objectGeometry = extrusion; + } + } + + geometry.Add(objectGeometry); + attributes.Add(objectAttributes); + } + } + + if (index < 0) index = doc.InstanceDefinitions.Add(idef_name, idef_description, Point3d.Origin, geometry, attributes); + else if (!doc.InstanceDefinitions.ModifyGeometry(index, geometry, attributes)) index = -1; + + if (index >= 0) idMap[element.Id] = doc.InstanceDefinitions[index].Id; + } + + return index >= 0; + } + #endregion + } +} diff --git a/src/RhinoInside.Revit.GH/Types/GeometricElement+ModelContent.cs b/src/RhinoInside.Revit.GH/Types/GeometricElement+ModelContent.cs new file mode 100644 index 000000000..002145423 --- /dev/null +++ b/src/RhinoInside.Revit.GH/Types/GeometricElement+ModelContent.cs @@ -0,0 +1,233 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using Grasshopper.Kernel.Types; +using Rhino.Geometry; +using ARDB = Autodesk.Revit.DB; +#if RHINO_8 +using Grasshopper.Rhinoceros; +using Grasshopper.Rhinoceros.Model; +using Grasshopper.Rhinoceros.Display; +using Grasshopper.Rhinoceros.Drafting; +using Grasshopper.Rhinoceros.Render; +#endif + +namespace RhinoInside.Revit.GH.Types +{ + using Convert.DocObjects; + using Convert.Geometry; + using External.DB.Extensions; + + partial class GeometricElement + { + #region ModelContent +#if RHINO_8 + readonly struct ModelAttributes + { + public static readonly ObjectDisplay DisplayByLayer = new ObjectDisplay.Attributes() { Color = ObjectDisplayColor.Value.ByLayer }; + public static readonly ObjectDrafting DraftingByLayer = new ObjectDrafting.Attributes() { Color = ObjectDraftingColor.Value.ByLayer }; + public static readonly ObjectRender RenderByLayer = new ObjectRender.Attributes() { Material = ObjectRenderMaterial.Value.ByLayer }; + + public static readonly ObjectDisplay DisplayByParent = new ObjectDisplay.Attributes() { Color = ObjectDisplayColor.Value.ByParent }; + public static readonly ObjectDrafting DraftingByParent = new ObjectDrafting.Attributes() { Color = ObjectDraftingColor.Value.ByParent }; + public static readonly ObjectRender RenderByParent = new ObjectRender.Attributes() { Material = ObjectRenderMaterial.Value.ByParent }; + + public static readonly ObjectDisplay DisplayByMaterial = new ObjectDisplay.Attributes() { Color = ObjectDisplayColor.Value.ByMaterial }; + } + + internal static ModelInstanceDefinition ToModelInstanceDefinition + ( + IDictionary idMap, + Transform transform, + ARDB.Element element, + ARDB.GeometryElement geometryElement + ) + { + if (idMap.TryGetValue(element.Id, out var modelContent)) + return modelContent as ModelInstanceDefinition; + + var geometryElementContent = geometryElement?.ToArray() ?? Array.Empty(); + if (geometryElementContent.Length == 0) + return null; + + if + ( + geometryElementContent.Length == 1 && + geometryElementContent[0] is ARDB.GeometryInstance geometryInstance && + geometryInstance.GetSymbol() is ARDB.ElementType symbol + ) + { + // Special case to simplify ARDB.FamilyInstance elements. + var instanceTransform = geometryInstance.Transform.ToTransform(); + return ToModelInstanceDefinition(idMap, instanceTransform * transform, symbol, geometryInstance.SymbolGeometry); + } + + var definition = new ModelInstanceDefinition.Attributes() + { + Path = NameConverter.EscapeName(element, out var description), + Notes = description + }; + + GeometryDecoder.UpdateGraphicAttributes(geometryElement); + + bool identity = transform.IsIdentity; + var objects = new List(geometryElementContent.Length); + foreach (var g in geometryElementContent) + { + using (GeometryDecoder.Context.Push()) + { + GeometryDecoder.UpdateGraphicAttributes(g); + + var shaded = false; + var geo = default(IGH_GeometricGoo); + switch (g) + { + case ARDB.Point point: + var pointGeometry = point.Coord.ToPoint3d(); + if (!identity) pointGeometry.Transform(transform); + geo = new GH_Point(pointGeometry); + break; + + case ARDB.PolyLine pline: + if (pline.NumberOfCoordinates == 0) continue; + var plineGeometry = pline.ToPolylineCurve(); + if (!identity) plineGeometry.Transform(transform); + geo = new GH_Curve(plineGeometry); + break; + + case ARDB.Curve curve: + var curveGeometry = curve.ToCurve(); + if (!identity) curveGeometry.Transform(transform); + geo = new GH_Curve(curveGeometry); + break; + + case ARDB.Mesh mesh: + if (mesh.NumTriangles == 0) continue; + var meshGeometry = mesh.ToMesh(); + if (!identity) meshGeometry.Transform(transform); + geo = new GH_Mesh(meshGeometry); + shaded = true; + break; + + case ARDB.Solid solid: + if (solid.Faces.IsEmpty) continue; + var solidGeometry = solid.ToBrep(); + if (!identity) solidGeometry.Transform(transform); + if (solidGeometry.TryGetExtrusion(out var extrusion)) geo = new GH_Extrusion(extrusion); + else if (solidGeometry.Faces.Count == 1) geo = new GH_Surface(solidGeometry); + else geo = new GH_Brep(solidGeometry); + shaded = true; + break; + + case ARDB.GeometryInstance instance: + using (GeometryDecoder.Context.Push()) + { + if (ToModelInstanceDefinition(idMap, Transform.Identity, instance.GetSymbol(), instance.SymbolGeometry) is ModelInstanceDefinition idef) + geo = new GH_InstanceReference(new InstanceReferenceGeometry(Guid.Empty, transform * instance.Transform.ToTransform()), idef); + } + break; + } + + if (geo is null) continue; + + var geometry = ModelObject.Cast(geo).ToAttributes(); + + var context = GeometryDecoder.Context.Peek; + if (context.Category is ARDB.Category category) + geometry.Layer = new Category(category).ToModelContent(idMap) as ModelLayer; + + if (g is ARDB.GeometryInstance) + { + geometry.Display = ModelAttributes.DisplayByLayer; + geometry.Drafting = ModelAttributes.DraftingByLayer; + geometry.Render = ModelAttributes.RenderByLayer; + } + else + { + geometry.Display = ModelAttributes.DisplayByLayer; + geometry.Drafting = ModelAttributes.DraftingByParent; + geometry.Render = ModelAttributes.RenderByParent; + + if (shaded) + { + + if (context.FaceMaterialId?.Length > 0) + { + bool hasPerFaceMaterials = false; + for (int f = 1; f < context.FaceMaterialId.Length && !hasPerFaceMaterials; ++f) + hasPerFaceMaterials |= context.FaceMaterialId[f] != context.FaceMaterialId[f - 1]; + + if (!hasPerFaceMaterials) + { + if (context.FaceMaterialId[0].IsValid()) + { + var faceMaterial = new Material(element.Document, context.FaceMaterialId[0]); + var faceModelMaterial = faceMaterial.ToModelContent(idMap) as ModelRenderMaterial; + geometry.Render = new ObjectRender.Attributes() { Material = faceModelMaterial }; + //geometry.Display = ModelAttributes.DisplayByMaterial; + } + } + } + } + } + + objects.Add(geometry); + } + } + + definition.Objects = objects.Select(x => x.ToModelData() as ModelObject).ToArray(); + + var modelInstanceDefinition = definition.ToModelData() as ModelInstanceDefinition; + idMap.Add(element.Id, modelInstanceDefinition); + return modelInstanceDefinition; + } + + internal override ModelContent ToModelContent(IDictionary idMap) + { + if (idMap.TryGetValue(Id, out var modelContent)) + return modelContent; + + if (Value is ARDB.Element element) + { + using (var options = new ARDB.Options() { DetailLevel = ARDB.ViewDetailLevel.Fine }) + { + using (var geometry = element.GetGeometry(options)) + { + using (var context = GeometryDecoder.Context.Push()) + { + context.Element = element; + context.Category = element.Category; + context.Material = geometry?.MaterialElement; + + var location = Location; + if (ToModelInstanceDefinition(idMap, Transform.PlaneToPlane(location, Plane.WorldXY), element, geometry) is ModelInstanceDefinition definition) + { + var elementToWorld = Transform.PlaneToPlane(Plane.WorldXY, TransformTo(location)); + var attributes = ModelObject.Cast(new GH_InstanceReference(new InstanceReferenceGeometry(Guid.Empty, elementToWorld), definition)).ToAttributes(); + attributes.Name = element.get_Parameter(ARDB.BuiltInParameter.ALL_MODEL_MARK)?.AsString() ?? string.Empty; + attributes.Url = element.get_Parameter(ARDB.BuiltInParameter.ALL_MODEL_URL)?.AsString() ?? string.Empty; + attributes.Layer = Category.ToModelContent(idMap) as ModelLayer; + attributes.Frame = location; + if (geometry?.MaterialElement is object) + { + var material = new Material(geometry.MaterialElement); + var modelMaterial = material.ToModelContent(idMap) as ModelRenderMaterial; + attributes.Render = new ObjectRender.Attributes() { Material = modelMaterial }; + } + + modelContent = attributes.ToModelData() as ModelContent; + //idMap.Add(Id, modelContent); + return modelContent; + } + } + } + } + } + + return null; + } +#endif + #endregion + + } +} diff --git a/src/RhinoInside.Revit.GH/Types/GeometricElement+Preview.cs b/src/RhinoInside.Revit.GH/Types/GeometricElement+Preview.cs new file mode 100644 index 000000000..6e1c9183e --- /dev/null +++ b/src/RhinoInside.Revit.GH/Types/GeometricElement+Preview.cs @@ -0,0 +1,544 @@ +using System; +using System.Collections.Generic; +using System.Diagnostics; +using System.Linq; +using Rhino; +using Rhino.Display; +using Rhino.Geometry; +using ARDB = Autodesk.Revit.DB; + +namespace RhinoInside.Revit.GH.Types +{ + using Convert.Display; + using Convert.Geometry; + using External.DB; + using External.DB.Extensions; + using Grasshopper.Kernel; + using Rhino.DocObjects; + + partial class GeometricElement + { + #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, + out ARDB.Material[] materials, out Mesh[] meshes, out Curve[] 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 } + ) + using (var geometry = element?.GetGeometry(options)) + { + if (geometry is null) + { + materials = null; + meshes = null; + wires = null; + } + else + { + var categoryMaterial = element.Category?.Material; + var elementMaterial = geometry.MaterialElement ?? categoryMaterial; + + wires = geometry.GetPreviewWires().Where(x => x is object).ToArray(); + meshes = geometry.Visibility == ARDB.Visibility.Visible ? + geometry.GetPreviewMeshes(element.Document, meshingParameters).ToArray() : + Array.Empty(); + materials = geometry.Visibility == ARDB.Visibility.Visible ? + geometry.GetPreviewMaterials(element.Document, elementMaterial).ToArray() : + Array.Empty(); + + if (wires.Length == 0 && meshes.Length == 0 && element.get_BoundingBox(options.View) is ARDB.BoundingBoxXYZ) + { + var subMeshes = new List(); + var subWires = new List(); + var subMaterials = new List(); + + foreach (var dependent in element.GetDependentElements(ElementFilters.ElementHasBoundingBoxFilter).Select(element.Document.GetElement)) + { + if (dependent.GetBoundingBoxXYZ(out var view) is null) + continue; + + using + ( + var dependentOptions = view is object ? + new ARDB.Options() { View = view, IncludeNonVisibleObjects = voidGeometry } : + new ARDB.Options() { DetailLevel = detailLevel == ARDB.ViewDetailLevel.Undefined ? ARDB.ViewDetailLevel.Medium : detailLevel, IncludeNonVisibleObjects = voidGeometry } + ) + using (var dependentGeometry = dependent?.GetGeometry(dependentOptions)) + { + if (dependentGeometry is object) + { + subWires.AddRange(dependentGeometry.GetPreviewWires().Where(x => x is object)); + if (!voidGeometry) + { + subMeshes.AddRange(dependentGeometry.GetPreviewMeshes(element.Document, meshingParameters)); + subMaterials.AddRange(dependentGeometry.GetPreviewMaterials(element.Document, elementMaterial)); + } + } + } + } + + meshes = subMeshes.ToArray(); + wires = subWires.ToArray(); + materials = subMaterials.ToArray(); + } + + foreach (var mesh in meshes) + mesh.Normals.ComputeNormals(); + } + } + } + + class Preview : IDisposable + { + readonly GeometricElement geometricElement; + readonly BoundingBox clippingBox; + public readonly MeshingParameters MeshingParameters; + public Rhino.Display.DisplayMaterial[] materials; + public Mesh[] meshes; + public Curve[] wires; + public Curve[] highlights; + static List previewsQueue; + + void Build() + { + if (!geometricElement.IsValid || !clippingBox.IsValid) + { + materials = Array.Empty(); + meshes = Array.Empty(); + wires = Array.Empty(); + highlights = Array.Empty(); + } + 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; + + 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(ElementFilters.ElementHasBoundingBoxFilter)); + break; + } + + //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 + { + 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) + { + 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 = 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(); + } + } + } + } + + static void BuildPreviews(ARDB.Document _, bool cancelled) + { + var previews = previewsQueue; + previewsQueue = null; + + if (cancelled) + return; + + // Sort in reverse order depending on how 'big' is the element on screen. + // The bigger the more at the end on the list. + previews.Sort((x, y) => (x.clippingBox.Diagonal.Length < y.clippingBox.Diagonal.Length) ? -1 : +1); + BuildPreviews(cancelled, previews); + } + + static void BuildPreviews(bool cancelled, List previews) + { + if (cancelled) + return; + + var stopWatch = new Stopwatch(); + + int count = 0; + while ((count = previews.Count) > 0) + { + // Draw the biggest elements first. + // The biggest element is at the end of previews List, this way no realloc occurs when removing it + + int last = count - 1; + var preview = previews[last]; + previews.RemoveAt(last); + + stopWatch.Start(); + preview.Build(); + stopWatch.Stop(); + + // If building those previews take use more than 200 ms we return to Revit, to keep it 'interactive'. + if (stopWatch.ElapsedMilliseconds > 200) + break; + } + + // RhinoDoc.ActiveDoc.Views.Redraw is synchronous :( + // better use RhinoView.Redraw that just invalidate the view, the OS will update it when possible + foreach (var view in RhinoDoc.ActiveDoc.Views) + view.Redraw(); + + // If there are pending previews to generate enqueue BuildPreviews again + if (previews.Count > 0) + Revit.EnqueueReadAction((_, cancel) => BuildPreviews(cancel, previews)); + else + RhinoDoc.ActiveDoc.Views.Redraw(); + } + + Preview(GeometricElement element) + { + geometricElement = element; + clippingBox = element.ClippingBox; + MeshingParameters = element._MeshingParameters; + } + + public static Preview OrderNew(GeometricElement element) + { + if (previewsQueue is null) + { + previewsQueue = new List(); + Revit.EnqueueReadAction((doc, cancel) => BuildPreviews(doc, cancel)); + } + + var preview = new Preview(element); + previewsQueue.Add(preview); + return preview; + } + + void IDisposable.Dispose() + { + if (meshes is object) + { + foreach (var mesh in meshes) + mesh.Dispose(); + + meshes = null; + } + + if (wires is object) + { + foreach (var wire in wires) + wire.Dispose(); + + wires = null; + } + + if (highlights is object) + { + foreach (var highlight in highlights) + highlight.Dispose(); + + highlights = null; + } + } + } + + MeshingParameters _MeshingParameters; + Preview _GeometryPreview; + Preview GeometryPreview + { + get { return _GeometryPreview ?? (_GeometryPreview = Preview.OrderNew(this)); } + set { if (_GeometryPreview != value) _GeometryPreview = value; } + } + + public Rhino.Display.DisplayMaterial[] TryGetPreviewMaterials() + { + return GeometryPreview.materials; + } + + public Mesh[] TryGetPreviewMeshes(MeshingParameters parameters) + { + if (!ReferenceEquals(_MeshingParameters, parameters)) + { + _MeshingParameters = parameters; + if (_GeometryPreview is object) + { + if (_GeometryPreview.MeshingParameters?.RelativeTolerance != _MeshingParameters?.RelativeTolerance) + GeometryPreview = null; + } + } + + return GeometryPreview.meshes; + } + + public Mesh[] TryGetPreviewMeshes() => GeometryPreview.meshes; + + public Curve[] TryGetPreviewWires() => GeometryPreview.wires; + + public Curve[] TryGetPreviewHighlights() => GeometryPreview.highlights; + #endregion + + protected override void SubInvalidateGraphics() + { + using (_GeometryPreview) _GeometryPreview = null; + _MeshingParameters = null; + + base.SubInvalidateGraphics(); + } + + public override BoundingBox GetBoundingBox(Transform xform) + { + if (Value is ARDB.Element element) + { + if (!xform.IsIdentity) + { + var meshes = TryGetPreviewMeshes(); + var wires = TryGetPreviewWires(); + if (meshes is null && wires is null) + BuildPreview(element, default, ARDB.ViewDetailLevel.Medium, out var _, out meshes, out wires); + + if (meshes?.Length > 0 || wires?.Length > 0) + { + var bbox = BoundingBox.Empty; + + foreach (var mesh in meshes) + bbox.Union(mesh.GetBoundingBox(xform)); + + foreach (var wire in wires) + bbox.Union(wire.GetBoundingBox(xform)); + + return bbox; + } + } + } + + return base.GetBoundingBox(xform); + } + + #region IGH_PreviewData + protected override void DrawViewportMeshes(GH_PreviewMeshArgs args) + { + if (!IsValid) + return; + + var meshes = TryGetPreviewMeshes(args.MeshingParameters); + if (meshes is null) + 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 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); + } + + protected override void DrawViewportWires(GH_PreviewWireArgs args) + { + if (!IsValid) + return; + + var thickness = args.Thickness * args.Pipeline.DpiScale; + var color = args.Color; + + var drawBox = true; + var higlights = TryGetPreviewHighlights(); + if (higlights is object && higlights.Length > 0) + { + 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) + { + drawBox = false; + DrawWires(args.Pipeline, wires, color, thickness); + } + + 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() + { + 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 + + #region IGH_PreviewMeshData + void IGH_PreviewMeshData.DestroyPreviewMeshes() => SubInvalidateGraphics(); + + Mesh[] IGH_PreviewMeshData.GetPreviewMeshes() => TryGetPreviewMeshes(); + #endregion + } +} diff --git a/src/RhinoInside.Revit.GH/Types/GeometricElement.cs b/src/RhinoInside.Revit.GH/Types/GeometricElement.cs index c2fdd54fb..f18618357 100644 --- a/src/RhinoInside.Revit.GH/Types/GeometricElement.cs +++ b/src/RhinoInside.Revit.GH/Types/GeometricElement.cs @@ -1,34 +1,15 @@ -using System; -using System.Collections.Generic; -using System.Diagnostics; -using System.Linq; using Grasshopper.Kernel; -using Grasshopper.Kernel.Types; -using Rhino; -using Rhino.Display; -using Rhino.DocObjects; -using Rhino.Geometry; using ARDB = Autodesk.Revit.DB; -#if RHINO_8 -using Grasshopper.Rhinoceros; -using Grasshopper.Rhinoceros.Model; -using Grasshopper.Rhinoceros.Display; -using Grasshopper.Rhinoceros.Render; -#endif namespace RhinoInside.Revit.GH.Types { - using Convert.Display; - using Convert.DocObjects; - using Convert.Geometry; - using External.DB; using External.DB.Extensions; [Kernel.Attributes.Name("Geometric Element")] public interface IGH_GeometricElement : IGH_GraphicalElement { } [Kernel.Attributes.Name("Geometric Element")] - public class GeometricElement : GraphicalElement, + public partial class GeometricElement : GraphicalElement, IGH_GeometricElement, IHostElementAccess, IGH_PreviewMeshData, @@ -48,987 +29,6 @@ public GeometricElement(ARDB.Element element) : base(element) { } return element.HasGeometry(); } - protected override void SubInvalidateGraphics() - { - using (_GeometryPreview) _GeometryPreview = null; - _MeshingParameters = null; - - base.SubInvalidateGraphics(); - } - - public override BoundingBox GetBoundingBox(Transform xform) - { - if (Value is ARDB.Element element) - { - if (!xform.IsIdentity) - { - var meshes = TryGetPreviewMeshes(); - var wires = TryGetPreviewWires(); - if (meshes is null && wires is null) - BuildPreview(element, default, ARDB.ViewDetailLevel.Medium, out var _, out meshes, out wires); - - if (meshes?.Length > 0 || wires?.Length > 0) - { - var bbox = BoundingBox.Empty; - - foreach (var mesh in meshes) - bbox.Union(mesh.GetBoundingBox(xform)); - - foreach (var wire in wires) - bbox.Union(wire.GetBoundingBox(xform)); - - return bbox; - } - } - } - - return base.GetBoundingBox(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, - out ARDB.Material[] materials, out Mesh[] meshes, out Curve[] 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 } - ) - using (var geometry = element?.GetGeometry(options)) - { - if (geometry is null) - { - materials = null; - meshes = null; - wires = null; - } - else - { - var categoryMaterial = element.Category?.Material; - var elementMaterial = geometry.MaterialElement ?? categoryMaterial; - - wires = geometry.GetPreviewWires().Where(x => x is object).ToArray(); - meshes = geometry.Visibility == ARDB.Visibility.Visible ? - geometry.GetPreviewMeshes(element.Document, meshingParameters).ToArray() : - Array.Empty(); - materials = geometry.Visibility == ARDB.Visibility.Visible ? - geometry.GetPreviewMaterials(element.Document, elementMaterial).ToArray() : - Array.Empty(); - - if (wires.Length == 0 && meshes.Length == 0 && element.get_BoundingBox(options.View) is ARDB.BoundingBoxXYZ) - { - var subMeshes = new List(); - var subWires = new List(); - var subMaterials = new List(); - - foreach (var dependent in element.GetDependentElements(ElementFilters.ElementHasBoundingBoxFilter).Select(element.Document.GetElement)) - { - if (dependent.GetBoundingBoxXYZ(out var view) is null) - continue; - - using - ( - var dependentOptions = view is object ? - new ARDB.Options() { View = view, IncludeNonVisibleObjects = voidGeometry } : - new ARDB.Options() { DetailLevel = detailLevel == ARDB.ViewDetailLevel.Undefined ? ARDB.ViewDetailLevel.Medium : detailLevel, IncludeNonVisibleObjects = voidGeometry } - ) - using (var dependentGeometry = dependent?.GetGeometry(dependentOptions)) - { - if (dependentGeometry is object) - { - subWires.AddRange(dependentGeometry.GetPreviewWires().Where(x => x is object)); - if (!voidGeometry) - { - subMeshes.AddRange(dependentGeometry.GetPreviewMeshes(element.Document, meshingParameters)); - subMaterials.AddRange(dependentGeometry.GetPreviewMaterials(element.Document, elementMaterial)); - } - } - } - } - - meshes = subMeshes.ToArray(); - wires = subWires.ToArray(); - materials = subMaterials.ToArray(); - } - - foreach (var mesh in meshes) - mesh.Normals.ComputeNormals(); - } - } - } - - class Preview : IDisposable - { - readonly GeometricElement geometricElement; - readonly BoundingBox clippingBox; - public readonly MeshingParameters MeshingParameters; - public Rhino.Display.DisplayMaterial[] materials; - public Mesh[] meshes; - public Curve[] wires; - public Curve[] highlights; - static List previewsQueue; - - void Build() - { - if (!geometricElement.IsValid || !clippingBox.IsValid) - { - materials = Array.Empty(); - meshes = Array.Empty(); - wires = Array.Empty(); - highlights = Array.Empty(); - } - 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; - - 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(ElementFilters.ElementHasBoundingBoxFilter)); - break; - } - - //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 - { - 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) - { - 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 = 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(); - } - } - } - } - - static void BuildPreviews(ARDB.Document _, bool cancelled) - { - var previews = previewsQueue; - previewsQueue = null; - - if (cancelled) - return; - - // Sort in reverse order depending on how 'big' is the element on screen. - // The bigger the more at the end on the list. - previews.Sort((x, y) => (x.clippingBox.Diagonal.Length < y.clippingBox.Diagonal.Length) ? -1 : +1); - BuildPreviews(cancelled, previews); - } - - static void BuildPreviews(bool cancelled, List previews) - { - if (cancelled) - return; - - var stopWatch = new Stopwatch(); - - int count = 0; - while ((count = previews.Count) > 0) - { - // Draw the biggest elements first. - // The biggest element is at the end of previews List, this way no realloc occurs when removing it - - int last = count - 1; - var preview = previews[last]; - previews.RemoveAt(last); - - stopWatch.Start(); - preview.Build(); - stopWatch.Stop(); - - // If building those previews take use more than 200 ms we return to Revit, to keep it 'interactive'. - if (stopWatch.ElapsedMilliseconds > 200) - break; - } - - // RhinoDoc.ActiveDoc.Views.Redraw is synchronous :( - // better use RhinoView.Redraw that just invalidate the view, the OS will update it when possible - foreach (var view in RhinoDoc.ActiveDoc.Views) - view.Redraw(); - - // If there are pending previews to generate enqueue BuildPreviews again - if (previews.Count > 0) - Revit.EnqueueReadAction((_, cancel) => BuildPreviews(cancel, previews)); - else - RhinoDoc.ActiveDoc.Views.Redraw(); - } - - Preview(GeometricElement element) - { - geometricElement = element; - clippingBox = element.ClippingBox; - MeshingParameters = element._MeshingParameters; - } - - public static Preview OrderNew(GeometricElement element) - { - if (previewsQueue is null) - { - previewsQueue = new List(); - Revit.EnqueueReadAction((doc, cancel) => BuildPreviews(doc, cancel)); - } - - var preview = new Preview(element); - previewsQueue.Add(preview); - return preview; - } - - void IDisposable.Dispose() - { - if (meshes is object) - { - foreach (var mesh in meshes) - mesh.Dispose(); - - meshes = null; - } - - if (wires is object) - { - foreach (var wire in wires) - wire.Dispose(); - - wires = null; - } - - if (highlights is object) - { - foreach (var highlight in highlights) - highlight.Dispose(); - - highlights = null; - } - } - } - - MeshingParameters _MeshingParameters; - Preview _GeometryPreview; - Preview GeometryPreview - { - get { return _GeometryPreview ?? (_GeometryPreview = Preview.OrderNew(this)); } - set { if (_GeometryPreview != value) _GeometryPreview = value; } - } - - public Rhino.Display.DisplayMaterial[] TryGetPreviewMaterials() - { - return GeometryPreview.materials; - } - - public Mesh[] TryGetPreviewMeshes(MeshingParameters parameters) - { - if (!ReferenceEquals(_MeshingParameters, parameters)) - { - _MeshingParameters = parameters; - if (_GeometryPreview is object) - { - if (_GeometryPreview.MeshingParameters?.RelativeTolerance != _MeshingParameters?.RelativeTolerance) - GeometryPreview = null; - } - } - - return GeometryPreview.meshes; - } - - public Mesh[] TryGetPreviewMeshes() => GeometryPreview.meshes; - - public Curve[] TryGetPreviewWires() => GeometryPreview.wires; - - public Curve[] TryGetPreviewHighlights() => GeometryPreview.highlights; - #endregion - - #region IGH_PreviewData - protected override void DrawViewportMeshes(GH_PreviewMeshArgs args) - { - if (!IsValid) - return; - - var meshes = TryGetPreviewMeshes(args.MeshingParameters); - if (meshes is null) - 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 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); - } - - protected override void DrawViewportWires(GH_PreviewWireArgs args) - { - if (!IsValid) - return; - - var thickness = args.Thickness * args.Pipeline.DpiScale; - var color = args.Color; - - var drawBox = true; - var higlights = TryGetPreviewHighlights(); - if (higlights is object && higlights.Length > 0) - { - 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) - { - drawBox = false; - DrawWires(args.Pipeline, wires, color, thickness); - } - - 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() - { - 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 - - #region IGH_PreviewMeshData - void IGH_PreviewMeshData.DestroyPreviewMeshes() => SubInvalidateGraphics(); - - Mesh[] IGH_PreviewMeshData.GetPreviewMeshes() => TryGetPreviewMeshes(); - #endregion - - #region IGH_BakeAwareElement - static ObjectAttributes PeekAttributes(IDictionary idMap, RhinoDoc doc, ObjectAttributes att, ARDB.Document document) - { - var context = GeometryDecoder.Context.Peek; - var attributes = new ObjectAttributes(); - - if (context.Category is ARDB.Category category) - { - if (new Category(category).BakeElement(idMap, false, doc, att, out var layerGuid)) - attributes.LayerIndex = doc.Layers.FindId(layerGuid).Index; - } - - if (context.Material is ARDB.Material material) - { - if (new Material(material).BakeElement(idMap, false, doc, att, out var materialGuid)) - { - attributes.MaterialSource = ObjectMaterialSource.MaterialFromObject; - attributes.MaterialIndex = doc.Materials.FindId(materialGuid).Index; - } - } - - return attributes; - } - - static System.Drawing.Color NoBlack(System.Drawing.Color value) - { - return (value.R == 0 && value.G == 0 && value.B == 0) ? System.Drawing.Color.FromArgb(value.A, 1, 1, 1) : value; - } - - protected internal static bool BakeGeometryElement - ( - IDictionary idMap, - bool overwrite, - RhinoDoc doc, - ObjectAttributes att, - Transform transform, - ARDB.Element element, - ARDB.GeometryElement geometryElement, - out int index - ) - { - // 1. Check if is already cloned - if (idMap.TryGetValue(element.Id, out var guid)) - { - index = doc.InstanceDefinitions.FindId(guid).Index; - return true; - } - - var geometryElementContent = geometryElement.ToArray(); - if (geometryElementContent.Length < 1) - { - index = -1; - return false; - } - else if - ( - geometryElementContent.Length == 1 && - geometryElementContent[0] is ARDB.GeometryInstance geometryInstance && - geometryInstance.GetSymbol() is ARDB.ElementType symbol - ) - { - // Special case to simplify ARDB.FamilyInstance elements. - var instanceTransform = geometryInstance.Transform.ToTransform(); - return BakeGeometryElement(idMap, false, doc, att, instanceTransform * transform, symbol, geometryInstance.SymbolGeometry, out index); - } - - // Get a Unique Instance Definition name. - var idef_name = NameConverter.EscapeName(element, out var idef_description); - - // 2. Check if already exist - index = doc.InstanceDefinitions.Find(idef_name)?.Index ?? -1; - - // 3. Update if necessary - if (index < 0 || overwrite) - { - bool identity = transform.IsIdentity; - - GeometryDecoder.UpdateGraphicAttributes(geometryElement); - - var geometry = new List(geometryElementContent.Length); - var attributes = new List(geometryElementContent.Length); - - foreach (var g in geometryElementContent) - { - using (GeometryDecoder.Context.Push()) - { - GeometryDecoder.UpdateGraphicAttributes(g); - - var geo = default(GeometryBase); - switch (g) - { - case ARDB.Mesh mesh: if(mesh.NumTriangles > 0) geo = mesh.ToMesh(); break; - case ARDB.Solid solid: if(!solid.Faces.IsEmpty) geo = solid.ToBrep(); break; - case ARDB.Curve curve: geo = curve.ToCurve(); break; - case ARDB.PolyLine pline: if (pline.NumberOfCoordinates > 0) geo = pline.ToPolylineCurve(); break; - case ARDB.GeometryInstance instance: - using (GeometryDecoder.Context.Push()) - { - if (BakeGeometryElement(idMap, false, doc, att, Transform.Identity, instance.GetSymbol(), instance.SymbolGeometry, out var idefIndex)) - geo = new InstanceReferenceGeometry(doc.InstanceDefinitions[idefIndex].Id, instance.Transform.ToTransform()); - } - break; - } - - if (geo is null) continue; - if (!identity) geo.Transform(transform); - - var geoAtt = PeekAttributes(idMap, doc, att, element.Document); - - // In case geo is a Brep and has different materials per face. - var context = GeometryDecoder.Context.Peek; - if (context.FaceMaterialId?.Length > 0) - { - bool hasPerFaceMaterials = false; - { - for (int f = 1; f < context.FaceMaterialId.Length && !hasPerFaceMaterials; ++f) - hasPerFaceMaterials |= context.FaceMaterialId[f] != context.FaceMaterialId[f - 1]; - } - - if (hasPerFaceMaterials && geo is Brep brep) - { - // Solve baseMaterial - var baseMaterial = Rhino.DocObjects.Material.DefaultMaterial; - if (geoAtt.MaterialSource == ObjectMaterialSource.MaterialFromLayer) - { - baseMaterial = doc.Materials[doc.Layers[geoAtt.LayerIndex].RenderMaterialIndex]; - var objectColor = new Material(context.Category.Material).ObjectColor; - geoAtt.ColorSource = ObjectColorSource.ColorFromObject; - geoAtt.ObjectColor = NoBlack(baseMaterial.DiffuseColor); - } - else if (geoAtt.MaterialSource == ObjectMaterialSource.MaterialFromObject) - { - baseMaterial = doc.Materials[geoAtt.MaterialIndex]; - var objectColor = new Material(context.Material).ObjectColor; -#if RHINO_8 - geoAtt.ColorSource = ObjectColorSource.ColorFromMaterial; -#else - geoAtt.ColorSource = ObjectColorSource.ColorFromObject; - geoAtt.ObjectColor = NoBlack(baseMaterial.DiffuseColor); -#endif - } - - // Create a new material for this brep - var brepMaterial = new Rhino.DocObjects.Material(baseMaterial); - - foreach (var face in brep.Faces) - { - var faceMaterialId = context.FaceMaterialId[face.SurfaceIndex]; - if (faceMaterialId != (context.Material?.Id ?? ARDB.ElementId.InvalidElementId)) - { - var faceMaterial = new Material(element.Document, faceMaterialId); - if (faceMaterial.BakeElement(idMap, false, doc, att, out var materialGuid)) - { - face.MaterialChannelIndex = brepMaterial.MaterialChannelIndexFromId(materialGuid, true); - face.PerFaceColor = NoBlack(faceMaterial.ObjectColor); - } - } - else - { - face.ClearMaterialChannelIndex(); - face.PerFaceColor = System.Drawing.Color.Empty; - } - } - - geoAtt.MaterialIndex = doc.Materials.Add(brepMaterial); - geoAtt.MaterialSource = ObjectMaterialSource.MaterialFromObject; - } - else - { - if (context.FaceMaterialId[0].IsValid()) - { - var faceMaterial = new Material(element.Document, context.FaceMaterialId[0]); - if (faceMaterial.BakeElement(idMap, false, doc, att, out var materialGuid)) - { - geoAtt.MaterialIndex = doc.Materials.FindId(materialGuid).Index; - geoAtt.MaterialSource = ObjectMaterialSource.MaterialFromObject; -#if RHINO_8 - geoAtt.ColorSource = ObjectColorSource.ColorFromMaterial; -#else - geoAtt.ColorSource = ObjectColorSource.ColorFromObject; - geoAtt.ObjectColor = NoBlack(faceMaterial.ObjectColor); -#endif - if ((geo as Brep)?.TryGetExtrusion(out var extrusion) is true) - geo = extrusion; - } - } - else - { - if ((geo as Brep)?.TryGetExtrusion(out var extrusion) is true) - geo = extrusion; - } - } - } - - geometry.Add(geo); - attributes.Add(geoAtt); - } - } - - if (index < 0) index = doc.InstanceDefinitions.Add(idef_name, idef_description, Point3d.Origin, geometry, attributes); - else if (!doc.InstanceDefinitions.ModifyGeometry(index, geometry, attributes)) index = -1; - - if (index >= 0) idMap[element.Id] = doc.InstanceDefinitions[index].Id; - } - - return index >= 0; - } - - bool IGH_BakeAwareData.BakeGeometry(RhinoDoc doc, ObjectAttributes att, out Guid guid) => - BakeElement(new Dictionary(), true, doc, att, out guid); - - public virtual bool BakeElement - ( - IDictionary idMap, - bool overwrite, - RhinoDoc doc, - ObjectAttributes att, - out Guid guid - ) - { - // 1. Check if is already cloned - guid = Guid.Empty; - - // 3. Update if necessary - if (Value is ARDB.Element element) - { - using (var options = new ARDB.Options() { DetailLevel = ARDB.ViewDetailLevel.Fine }) - { - using (var geometry = element.GetGeometry(options)) - { - if (geometry is object) - { - using (var context = GeometryDecoder.Context.Push()) - { - context.Element = element; - context.Category = element.Category; - context.Material = element.Category?.Material; - - var location = element.Category is null || element.Category.Parent is object ? - Plane.WorldXY : - Location; - - var worldToElement = Transform.PlaneToPlane(location, Plane.WorldXY); - if (BakeGeometryElement(idMap, overwrite, doc, att, worldToElement, element, geometry, out var idefIndex)) - { - att = att?.Duplicate() ?? doc.CreateDefaultAttributes(); - att.Space = ActiveSpace.ModelSpace; - att.ViewportId = Guid.Empty; - att.Name = element.get_Parameter(ARDB.BuiltInParameter.ALL_MODEL_MARK)?.AsString() ?? string.Empty; - att.Url = element.get_Parameter(ARDB.BuiltInParameter.ALL_MODEL_URL)?.AsString() ?? string.Empty; - - if (Category.BakeElement(idMap, false, doc, att, out var layerGuid)) - att.LayerIndex = doc.Layers.FindId(layerGuid).Index; - - guid = doc.Objects.AddInstanceObject(idefIndex, Transform.PlaneToPlane(Plane.WorldXY, location), att); - - // We don't want geometry on the active viewport but on its own. - doc.Objects.ModifyAttributes(guid, att, quiet: true); - } - } - - if (guid != Guid.Empty) - return true; - } - } - } - } - - return false; - } - #endregion - - #region ModelContent -#if RHINO_8 - static void PeekModelAttributes(IDictionary idMap, ModelObject.Attributes attributes, ARDB.Document document) - { - var context = GeometryDecoder.Context.Peek; - - if (context.Category is ARDB.Category category) - { - attributes.Layer = new Category(category).ToModelContent(idMap) as ModelLayer; - } - - if (context.Material is ARDB.Material material) - { - if (new Material(material).ToModelContent(idMap) is ModelRenderMaterial renderMaterial) - attributes.Render = new ObjectRender.Attributes() { Material = renderMaterial }; - } - } - - internal static ModelInstanceDefinition ToModelInstanceDefinition - ( - IDictionary idMap, - Transform transform, - ARDB.Element element, - ARDB.GeometryElement geometryElement - ) - { - if (idMap.TryGetValue(element.Id, out var modelContent)) - return modelContent as ModelInstanceDefinition; - - var geometryElementContent = geometryElement?.ToArray() ?? Array.Empty(); - - if - ( - geometryElementContent.Length == 1 && - geometryElementContent[0] is ARDB.GeometryInstance geometryInstance && - geometryInstance.GetSymbol() is ARDB.ElementType symbol - ) - { - // Special case to simplify ARDB.FamilyInstance elements. - var instanceTransform = geometryInstance.Transform.ToTransform(); - return ToModelInstanceDefinition(idMap, instanceTransform * transform, symbol, geometryInstance.SymbolGeometry); - } - - var attributes = new ModelInstanceDefinition.Attributes() - { - Path = NameConverter.EscapeName(element, out var description), - Notes = description - }; - - GeometryDecoder.UpdateGraphicAttributes(geometryElement); - - bool identity = transform.IsIdentity; - var objects = new List(geometryElementContent.Length); - foreach (var g in geometryElementContent) - { - using (GeometryDecoder.Context.Push()) - { - GeometryDecoder.UpdateGraphicAttributes(g); - - var shaded = false; - var geo = default(IGH_GeometricGoo); - switch (g) - { - case ARDB.Point point: - var pointGeometry = point.Coord.ToPoint3d(); - if (!identity) pointGeometry.Transform(transform); - geo = new GH_Point(pointGeometry); - break; - - case ARDB.Mesh mesh: - if (mesh.NumTriangles == 0) continue; - var meshGeometry = mesh.ToMesh(); - if (!identity) meshGeometry.Transform(transform); - geo = new GH_Mesh(meshGeometry); - shaded = true; - break; - - case ARDB.Solid solid: - if (solid.Faces.IsEmpty) continue; - var solidGeometry = solid.ToBrep(); - if (!identity) solidGeometry.Transform(transform); - if (solidGeometry.TryGetExtrusion(out var extrusion)) geo = new GH_Extrusion(extrusion); - else if (solidGeometry.Faces.Count == 1) geo = new GH_Surface(solidGeometry); - else geo = new GH_Brep(solidGeometry); - shaded = true; - break; - - case ARDB.Curve curve: - var curveGeometry = curve.ToCurve(); - if (!identity) curveGeometry.Transform(transform); - geo = new GH_Curve(curveGeometry); - break; - - case ARDB.PolyLine pline: - if (pline.NumberOfCoordinates == 0) continue; - var plineGeometry = pline.ToPolylineCurve(); - if (!identity) plineGeometry.Transform(transform); - geo = new GH_Curve(plineGeometry); - break; - - case ARDB.GeometryInstance instance: - using (GeometryDecoder.Context.Push()) - { - if (ToModelInstanceDefinition(idMap, Transform.Identity, instance.GetSymbol(), instance.SymbolGeometry) is ModelInstanceDefinition definition) - geo = new GH_InstanceReference(new InstanceReferenceGeometry(Guid.Empty, transform * instance.Transform.ToTransform()), definition); - } - break; - } - - if (geo is null) continue; - - var objectAttributes = ModelObject.Cast(geo).ToAttributes(); - PeekModelAttributes(idMap, objectAttributes, element.Document); - - if (shaded) - { - objectAttributes.Display = new ObjectDisplay.Attributes() { Color = ObjectDisplayColor.Value.ByMaterial }; - - var context = GeometryDecoder.Context.Peek; - if (context.FaceMaterialId?.Length > 0) - { - bool hasPerFaceMaterials = false; - for (int f = 1; f < context.FaceMaterialId.Length && !hasPerFaceMaterials; ++f) - hasPerFaceMaterials |= context.FaceMaterialId[f] != context.FaceMaterialId[f - 1]; - - if (!hasPerFaceMaterials) - { - var faceMaterial = new Material(element.Document, context.FaceMaterialId[0]); - var faceModelMaterial = faceMaterial.ToModelContent(idMap) as ModelRenderMaterial; - objectAttributes.Render = new ObjectRender.Attributes() { Material = faceModelMaterial }; - } - } - } - - objects.Add(objectAttributes); - } - } - - attributes.Objects = objects.Select(x => x.ToModelData() as ModelObject).ToArray(); - - var modelInstanceDefinition = attributes.ToModelData() as ModelInstanceDefinition; - idMap.Add(element.Id, modelInstanceDefinition); - return modelInstanceDefinition; - } - - internal override ModelContent ToModelContent(IDictionary idMap) - { - if (idMap.TryGetValue(Id, out var modelContent)) - return modelContent; - - if (Value is ARDB.Element element) - { - using (var options = new ARDB.Options() { DetailLevel = ARDB.ViewDetailLevel.Fine }) - { - using (var geometry = element.GetGeometry(options)) - { - using (var context = GeometryDecoder.Context.Push()) - { - context.Element = element; - context.Category = element.Category; - context.Material = element.Category?.Material; - - var location = Location; - if (ToModelInstanceDefinition(idMap, Transform.PlaneToPlane(location, Plane.WorldXY), element, geometry) is ModelInstanceDefinition definition) - { - var elementToWorld = Transform.PlaneToPlane(Plane.WorldXY, TransformTo(location)); - var attributes = ModelObject.Cast(new GH_InstanceReference(new InstanceReferenceGeometry(Guid.Empty, elementToWorld), definition)).ToAttributes(); - attributes.Name = element.get_Parameter(ARDB.BuiltInParameter.ALL_MODEL_MARK)?.AsString() ?? string.Empty; - attributes.Url = element.get_Parameter(ARDB.BuiltInParameter.ALL_MODEL_URL)?.AsString() ?? string.Empty; - attributes.Layer = Category.ToModelContent(idMap) as ModelLayer; - attributes.Frame = location; - - modelContent = attributes.ToModelData() as ModelContent; - //idMap.Add(Id, modelContent); - return modelContent; - } - } - } - } - } - - return null; - } -#endif - #endregion - #region IHostElementAccess GraphicalElement IHostElementAccess.HostElement => HostElement; diff --git a/src/RhinoInside.Revit.GH/Types/Instances/FamilyInstance.cs b/src/RhinoInside.Revit.GH/Types/Instances/FamilyInstance.cs index 5e2e072d2..3e155163e 100644 --- a/src/RhinoInside.Revit.GH/Types/Instances/FamilyInstance.cs +++ b/src/RhinoInside.Revit.GH/Types/Instances/FamilyInstance.cs @@ -67,7 +67,7 @@ out Guid guid var location = new Plane(transform.Origin.ToPoint3d(), transform.BasisX.ToVector3d(), transform.BasisY.ToVector3d()); var worldToElement = Transform.PlaneToPlane(location, Plane.WorldXY); - if (BakeGeometryElement(idMap, overwrite, doc, att, worldToElement, element, geometry, out var idefIndex)) + if (BakeGeometryElement(idMap, overwrite, doc, worldToElement, element, geometry, out var idefIndex)) { att = att?.Duplicate() ?? doc.CreateDefaultAttributes(); att.Name = element.get_Parameter(ARDB.BuiltInParameter.ALL_MODEL_MARK)?.AsString() ?? string.Empty; @@ -434,7 +434,7 @@ out Guid guid { if (geometry is ARDB.GeometryElement geometryElement) { - if (GeometricElement.BakeGeometryElement(idMap, overwrite, doc, att, Transform.Identity, element, geometry, out var idefIndex)) + if (GeometricElement.BakeGeometryElement(idMap, overwrite, doc, Transform.Identity, element, geometry, out var idefIndex)) guid = doc.InstanceDefinitions[idefIndex].Id; } diff --git a/src/RhinoInside.Revit.GH/Types/Materials/AppearanceAsset.cs b/src/RhinoInside.Revit.GH/Types/Materials/AppearanceAsset.cs index 6d79d523a..1ed5d024a 100755 --- a/src/RhinoInside.Revit.GH/Types/Materials/AppearanceAsset.cs +++ b/src/RhinoInside.Revit.GH/Types/Materials/AppearanceAsset.cs @@ -24,25 +24,14 @@ public override bool ConvertTo(out Q target) { if (base.ConvertTo(out target)) return true; -#if REVIT_2018 + if (typeof(Q).IsAssignableFrom(typeof(Grasshopper.Kernel.Types.GH_Material))) { - if (RhinoDoc.ActiveDoc is RhinoDoc doc) - { - if (Value is ARDB.AppearanceAssetElement appearance) - { - var renderMaterial = RenderMaterial.CreateBasicMaterial(Rhino.DocObjects.Material.DefaultMaterial, doc); - renderMaterial.Name = appearance.Name; - - using (var asset = appearance.GetRenderingAsset()) - renderMaterial.SimulateRenderingAsset(asset, doc); + if (Value?.ToRenderMaterial(RhinoDoc.ActiveDoc) is RenderMaterial renderMaterial) + target = (Q) (object) new Grasshopper.Kernel.Types.GH_Material(renderMaterial); - target = (Q) (object) new Grasshopper.Kernel.Types.GH_Material(renderMaterial); - return true; - } - } + return true; } -#endif return false; } @@ -59,65 +48,41 @@ public bool BakeElement out Guid guid ) { -#if REVIT_2018 // 1. Check if is already cloned if (idMap.TryGetValue(Id, out guid)) return true; - if (Value is ARDB.AppearanceAssetElement appearance) - { - if (BakeRenderMaterial(overwrite, doc, appearance.Name, out guid)) - idMap.Add(Id, guid); - } -#else - guid = Guid.Empty; -#endif - - return false; - } - -#if REVIT_2018 - internal bool BakeRenderMaterial - ( - bool overwrite, - RhinoDoc doc, - string materialName, - out Guid guid - ) - { if (Value is ARDB.AppearanceAssetElement appearance) { // 2. Check if already exist - var material = doc.RenderMaterials.FirstOrDefault(x => x.Name == materialName); + var target = doc.RenderMaterials.FindName(appearance.Name); - if (material is null) + // 3. Update if necessary + if (target is null || overwrite) { - material = RenderMaterial.CreateBasicMaterial(Rhino.DocObjects.Material.DefaultMaterial, doc); - material.Name = materialName; + var source = appearance.ToRenderMaterial(doc); + if (target is object) + { + target.BeginChange(RenderContent.ChangeContexts.Program); + if (!target.Replace(source)) target.MatchData(source); + target.EndChange(); + } + else if (doc.RenderMaterials.Add(source)) + { + target = source; + } } - if(material.DocumentOwner is null || overwrite) + if (target is object) { - if (material.DocumentOwner is object) - material.BeginChange(RenderContent.ChangeContexts.Program); - - using (var asset = appearance.GetRenderingAsset()) - material.SimulateRenderingAsset(asset, doc); - - if (material.DocumentOwner is object) - material.EndChange(); - else - doc.RenderMaterials.Add(material); + idMap.Add(Id, (guid = target.Id)); + return true; } - - guid = material.Id; - return true; } guid = Guid.Empty; return false; } -#endif #endregion } } diff --git a/src/RhinoInside.Revit.GH/Types/Materials/Material.cs b/src/RhinoInside.Revit.GH/Types/Materials/Material.cs index 778a82d72..01ea6e837 100644 --- a/src/RhinoInside.Revit.GH/Types/Materials/Material.cs +++ b/src/RhinoInside.Revit.GH/Types/Materials/Material.cs @@ -1,8 +1,11 @@ using System; using System.Collections.Generic; +using System.Linq; using Grasshopper.Kernel; using Rhino; +using Rhino.Display; using Rhino.DocObjects; +using Rhino.DocObjects.Tables; using Rhino.Render; using ARDB = Autodesk.Revit.DB; #if RHINO_8 @@ -14,6 +17,7 @@ namespace RhinoInside.Revit.GH.Types { using Convert.Render; using Convert.System.Drawing; + using External.DB; using External.DB.Extensions; [Kernel.Attributes.Name("Material")] @@ -56,13 +60,13 @@ public override bool ConvertTo(out Q target) if (typeof(Q).IsAssignableFrom(typeof(Grasshopper.Kernel.Types.GH_Material))) { if (IsEmpty) - target = (Q) (object) new Grasshopper.Kernel.Types.GH_Material(new Guid("{DEFADEFA-DEFA-DEFA-DEFA-DEFADEFADEFA}")); - else if (Value?.ToRenderMaterial(RhinoDoc.ActiveDoc) is Rhino.Render.RenderMaterial renderMaterial) + target = (Q) (object) new Grasshopper.Kernel.Types.GH_Material(DefaultRenderMaterial); + else if (Value?.ToRenderMaterial(RhinoDoc.ActiveDoc) is RenderMaterial renderMaterial) target = (Q) (object) new Grasshopper.Kernel.Types.GH_Material(renderMaterial); else target = default; - return true; + return true; } #if RHINO_8 @@ -93,99 +97,129 @@ out Guid guid if (idMap.TryGetValue(Id, out guid)) return true; - if (Value is ARDB.Material material) + var material = Value; + if (material is object || IsEmpty) { // 2. Check if already exist - var index = doc.Materials.Find(material.Name, true); - var mat = index < 0 ? - new Rhino.DocObjects.Material() { Name = material.Name } : - doc.Materials[index]; + var target = doc.RenderMaterials.FindName(material?.Name ?? DefaultRenderMaterialName); // 3. Update if necessary - if (index < 0 || overwrite) + if (target is null || overwrite) { -#if REVIT_2018 - if (AppearanceAsset is AppearanceAssetElement asset) + var source = material?.ToRenderMaterial(doc) ?? DefaultRenderMaterial; + if (target is object) { - if (asset.BakeRenderMaterial(overwrite, doc, material.Name, out var renderMaterialId)) - { - if (RenderContent.FromId(doc, renderMaterialId) is RenderMaterial renderMaterial) - { -#if RHINO_8 - try - { - renderMaterial.BeginChange(RenderContent.ChangeContexts.Program); - - if (!material.UseRenderAppearanceForShading) - { - var slot = renderMaterial.TextureChildSlotName(RenderMaterial.StandardChildSlots.Diffuse); - if (!renderMaterial.ChildSlotOn(slot)) - { - var diffuse = RenderContent.Create(ContentUuids.SingleColorTextureType, renderMaterial, slot, default, doc) as RenderTexture; - diffuse.Name = material.Name; - diffuse.Fields.Set("color-one", renderMaterial.Fields.GetField(RenderMaterial.BasicMaterialParameterNames.Diffuse).GetValue()); - renderMaterial.SetChildSlotAmount(slot, 100.0, RenderContent.ChangeContexts.Program); - renderMaterial.SetChildSlotOn(slot, true, RenderContent.ChangeContexts.Program); - } - } - - renderMaterial.Fields.Set(RenderMaterial.BasicMaterialParameterNames.Diffuse, material.Color.ToColor()); - } - finally { renderMaterial.EndChange(); } -#endif - renderMaterial.SimulateMaterial(ref mat, RenderTexture.TextureGeneration.Allow); - - if (mat.Name != material.Name) - { - mat.Name = material.Name; - mat.RenderMaterialInstanceId = Guid.Empty; - } - else mat.RenderMaterialInstanceId = renderMaterialId; - } - } + target.BeginChange(RenderContent.ChangeContexts.Program); + if (!target.Replace(source)) target.MatchData(source); + target.EndChange(); } - else -#endif + else if (doc.RenderMaterials.Add(source)) { - mat.DiffuseColor = material.Color.ToColor(); - mat.Shine = material.Shininess / 128.0 * Rhino.DocObjects.Material.MaxShine; - mat.Reflectivity = 1.0 / Math.Exp((1.0 - (material.Smoothness / 100.0)) * 10); - mat.Transparency = material.Transparency / 100.0; + target = source; } - - if (index < 0) { index = doc.Materials.Add(mat); mat = doc.Materials[index]; } - else if (overwrite) doc.Materials.Modify(mat, index, true); } - idMap.Add(Id, guid = mat.Id); - return true; + if (target is object) + { + guid = target.Id; + if (Id.IsValid()) idMap.Add(Id, guid); + return true; + } } return false; } - internal System.Drawing.Color ObjectColor + internal bool BakeSharedMaterial + ( + IDictionary idMap, + bool overwrite, + RhinoDoc doc, + out Guid guid + ) { - get + // We create this fake id because a material may be baked as shared or not. + var id = new ARDB.ElementId(-Id.ToValue()); + + // 1. Check if is already cloned + if (idMap.TryGetValue(id, out guid)) + return true; + + if (BakeElement(idMap, overwrite, doc, null, out var materialId)) { - if (Value is ARDB.Material material) + // 2. Check if already exist + var target = doc.Materials.FindName(materialId.ToString()); + if (target is object && target.RenderMaterialInstanceId != materialId) overwrite = true; + + // 3. Update if necessary + if (target is null || overwrite) { - var color = System.Drawing.Color.FromArgb - ( - 255 - (int) Math.Round(material.Transparency / 100.0 * 255.0), - material.Color.ToColor() - ); + var source = new Rhino.DocObjects.Material + { + Name = materialId.ToString(), + RenderMaterialInstanceId = materialId + }; - return color; + if (target is object) + doc.Materials.Modify(source, target.Index, quiet: true); + else + target = doc.Materials[doc.Materials.Add(source)]; } - return System.Drawing.Color.Empty; + if (target is object) + { + idMap.Add(id, (guid = target.Id)); + return true; + } } + + return false; + } + + internal System.Drawing.Color ObjectColor => Value.ToShadingMaterial(out var _, out var _); + #endregion + + #region DefaultRenderMaterial + internal const string DefaultRenderMaterialName = ""; + + static RenderMaterial _DefaultRenderMaterial => CreateDefaultMaterial(); + static RenderMaterial DefaultRenderMaterial => _DefaultRenderMaterial.MakeCopy() as RenderMaterial; + + static RenderMaterial CreateDefaultMaterial() + { + var color = new ColorRGBA(default(ARDB.Material).ToShadingMaterial(out var shininess, out var smoothness).ToArgb()); + var rgba = new Color4f((float) color.R, (float) color.G, (float) color.B, (float) color.A); + + var hsl = ColorHSL.CreateFromRGBA(color); + var emissionRGBA = ColorRGBA.CreateFromHSL(new ColorHSL(hsl.H, hsl.S * 0.5, hsl.L * 0.25)); + var emission = new Color4f((float) emissionRGBA.R, (float) emissionRGBA.G, (float) emissionRGBA.B, (float) emissionRGBA.A); + + var transparency = 1.0 - rgba.A; + var renderMaterial = RenderContentType.NewContentFromTypeId(ContentUuids.BasicMaterialType) as RenderMaterial; + renderMaterial.Hidden = true; + renderMaterial.Name = DefaultRenderMaterialName; + renderMaterial.Notes = "Default Revit Material"; + renderMaterial.Fields.Set(RenderMaterial.BasicMaterialParameterNames.Diffuse, rgba); + renderMaterial.Fields.Set(RenderMaterial.BasicMaterialParameterNames.Shine, shininess); + renderMaterial.Fields.Set(RenderMaterial.BasicMaterialParameterNames.Specular, Color4f.White); + renderMaterial.Fields.Set(RenderMaterial.BasicMaterialParameterNames.Transparency, transparency); + renderMaterial.Fields.Set(RenderMaterial.BasicMaterialParameterNames.TransparencyColor, Color4f.White); + renderMaterial.Fields.Set(RenderMaterial.BasicMaterialParameterNames.Emission, emission); + renderMaterial.Fields.Set(RenderMaterial.BasicMaterialParameterNames.Reflectivity, smoothness); + renderMaterial.Fields.Set(RenderMaterial.BasicMaterialParameterNames.ReflectivityColor, Color4f.White); + renderMaterial.Fields.Set(RenderMaterial.BasicMaterialParameterNames.Ior, transparency < 0.5 ? 1.0 : transparency + 0.52); + renderMaterial.Fields.Set("polish-amount", smoothness); + renderMaterial.Fields.Set("clarity-amount", smoothness); + renderMaterial.Fields.Set("fresnel-enabled", true); + + return renderMaterial; } #endregion #region ModelContent #if RHINO_8 + static readonly ModelRenderMaterial DefaultModelRenderMaterial = new ModelRenderMaterial(_DefaultRenderMaterial); + internal ModelContent ToModelContent(IDictionary idMap) { if (idMap.TryGetValue(Id, out var modelContent)) @@ -199,31 +233,11 @@ internal ModelContent ToModelContent(IDictionary i RenderMaterial = material.ToRenderMaterial(Grasshopper.Instances.ActiveRhinoDoc) }; -#if RHINO_8 - attributes.RenderMaterial.BeginChange(RenderContent.ChangeContexts.Program); - - if (!material.UseRenderAppearanceForShading) - { - var slot = attributes.RenderMaterial.TextureChildSlotName(RenderMaterial.StandardChildSlots.Diffuse); - if (!attributes.RenderMaterial.ChildSlotOn(slot)) - { - var diffuse = RenderContentType.NewContentFromTypeId(ContentUuids.SingleColorTextureType) as RenderTexture; - diffuse.Name = material.Name; - diffuse.Fields.Set("color-one", attributes.RenderMaterial.Fields.GetField(RenderMaterial.BasicMaterialParameterNames.Diffuse).GetValue()); - attributes.RenderMaterial.SetChild(diffuse, slot); - attributes.RenderMaterial.SetChildSlotAmount(slot, 100.0, RenderContent.ChangeContexts.Program); - attributes.RenderMaterial.SetChildSlotOn(slot, true, RenderContent.ChangeContexts.Program); - } - } - - attributes.RenderMaterial.Fields.Set(RenderMaterial.BasicMaterialParameterNames.Diffuse, material.Color.ToColor()); -#endif - idMap.Add(Id, modelContent = attributes.ToModelData() as ModelContent); return modelContent; } - return null; + return IsEmpty ? DefaultModelRenderMaterial : null; } #endif #endregion @@ -371,7 +385,7 @@ public double? Transparency if (value is object && Value is ARDB.Material material) { var intValue = (int) Math.Round(value.Value * 100.0); - if(0.0 > intValue || intValue > 100) + if (0.0 > intValue || intValue > 100) throw new ArgumentOutOfRangeException(nameof(Transparency), "Valid value range for transparency is [0.0, 1.0]"); if (material.Transparency != intValue) diff --git a/src/RhinoInside.Revit.GH/Types/ObjectStyles/Category.cs b/src/RhinoInside.Revit.GH/Types/ObjectStyles/Category.cs index 8849fc856..1b395e9e7 100644 --- a/src/RhinoInside.Revit.GH/Types/ObjectStyles/Category.cs +++ b/src/RhinoInside.Revit.GH/Types/ObjectStyles/Category.cs @@ -5,6 +5,8 @@ using Grasshopper.Kernel.Types; using Rhino; using Rhino.DocObjects; +using Rhino.DocObjects.Tables; +using Rhino.Render; using ARDB = Autodesk.Revit.DB; using ERDB = RhinoInside.Revit.External.DB; using DBXS = RhinoInside.Revit.External.DB.Schemas; @@ -18,6 +20,7 @@ namespace RhinoInside.Revit.GH.Types { + using Convert.Render; using Convert.System.Drawing; using External.DB.Extensions; @@ -309,67 +312,69 @@ out Guid guid if (idMap.TryGetValue(Id, out guid)) return true; - const string RootLayerName = "Revit"; - var PS = Layer.PathSeparator; - if (APIObject is ARDB.Category category) { - var fullLayerName = category.Parent is null ? - $"{RootLayerName}{PS}{category.CategoryType}{PS}{category.Name}" : - $"{RootLayerName}{PS}{category.CategoryType}{PS}{category.Parent.Name}{PS}{category.Name}"; + var elementPath = GetElementPath().ToArray(); // 2. Check if already exist - var index = doc.Layers.FindByFullPath(fullLayerName, -1); - var layer = index < 0 ? - Layer.GetDefaultLayerProperties() : - doc.Layers[index]; + var index = doc.Layers.FindByFullPath(string.Join("::", elementPath), -1); + var layer = index >= 0 && index < doc.Layers.Count ? doc.Layers[index] : null; // 3. Update if necessary if (index < 0 || overwrite) { if (index < 0) { - // Create Root Layer - new Category(category.Parent).BakeElement(idMap, false, doc, att, out var parentGuid); - - // Create Category Type Layer - if (category.Parent is null) + // Bake parent layers and create current one + var name = default(string); + var parentId = Guid.Empty; { - if (Types.CategoryType.NamedValues.TryGetValue((int) category.CategoryType, out var typeName)) + if (Parent is Category parent) + { + parent.BakeElement(idMap, overwrite: true, doc, default, out parentId); + name = elementPath.LastOrDefault(); + } + else { - var type = doc.Layers.FindByFullPath($"{RootLayerName}::{category.CategoryType}", -1); - if (type < 0) + var added = false; + foreach (var token in elementPath.TakeButLast(out name)) { - var typeLayer = Layer.GetDefaultLayerProperties(); - typeLayer.ParentLayerId = parentGuid; - typeLayer.Name = typeName; - type = doc.Layers.Add(typeLayer); + if (!added && doc.Manifest.FindName(token, ModelComponentType.Layer, parentId) is Layer current) + { + parentId = current.Id; + } + else + { + current = new Layer + { + Index = -1, + IsExpanded = false, + ParentLayerId = parentId, + Name = token, + Color = System.Drawing.Color.FromArgb(23, 107, 254), + }; + parentId = doc.Layers[doc.Layers.Add(current)].Id; + added = true; + } } - - parentGuid = doc.Layers[type].Id; } - } - layer.ParentLayerId = parentGuid; - layer.Name = category.Name; - layer.IsExpanded = false; - } - - // Linetype - { - var linetypeIndex = -1; - if (ProjectionLinePattern is LinePatternElement linePattern) - { - if (linePattern.BakeElement(idMap, false, doc, att, out var linetypeGuid)) - linetypeIndex = doc.Linetypes.FindId(linetypeGuid).Index; + layer = new Layer + { + Id = Guid.NewGuid(), + Index = -1, + Name = name, + IsExpanded = false, + ParentLayerId = parentId + }; } - layer.LinetypeIndex = linetypeIndex; } - // LineColor + // Linetype { - var lineColor = category.LineColor.ToColor(); - layer.PlotColor = lineColor.IsEmpty ? System.Drawing.Color.Black : lineColor; + layer.LinetypeIndex = ProjectionLinePattern.BakeElement(idMap, false, doc, att, out var linetypeGuid) ? + doc.Linetypes.FindId(linetypeGuid).Index : + -1; // Continuous } // Print Width @@ -379,27 +384,76 @@ out Guid guid ToLineWeight(ProjectionLineWeight); } - // Color + // LineColor { - var displayColor = category.CategoryType != ARDB.CategoryType.Model || - category.Root().ToBuiltInCategory() == ARDB.BuiltInCategory.OST_Lines ? - layer.PlotColor : - new Material(category.Material).ObjectColor; + var lineColor = category.LineColor.ToColor(); + layer.PlotColor = lineColor.IsEmpty ? System.Drawing.Color.Black : lineColor; + } - layer.Color = displayColor.IsEmpty ? System.Drawing.Color.FromArgb(0x7F, 0x7F, 0x7F) : displayColor; + // Color + { + layer.Color = category.Material.ToShadingMaterial(out var _, out var _); } // Material + if (category.CategoryType != ARDB.CategoryType.Annotation) { var materialIndex = -1; - if (Material is Material material) { - if (material.BakeElement(idMap, false, doc, att, out var materialGuid)) - materialIndex = doc.Materials.FindId(materialGuid).Index; + var material = new Material(category.Material); + if (material.BakeElement(idMap, false, doc, att, out var renderMaterialInstanceId)) + { + materialIndex = layer.RenderMaterialIndex; + if (materialIndex < 0) materialIndex = doc.Materials.FindName(layer.Id.ToString())?.Index ?? -1; + + var layerMaterial = materialIndex >= 0 && materialIndex < doc.Materials.Count ? doc.Materials[materialIndex] : null; + if (layerMaterial?.IsDeleted is true || layerMaterial?.IsReference is true) layerMaterial = null; + if (layerMaterial?.RenderMaterialInstanceId != renderMaterialInstanceId) + { + layerMaterial = new Rhino.DocObjects.Material() + { + Name = layer.Id.ToString(), + RenderMaterialInstanceId = renderMaterialInstanceId + }; + + if (materialIndex < 0) materialIndex = doc.Materials.Add(layerMaterial); + else doc.Materials.Modify(layerMaterial, materialIndex, quiet: true); + } + } } layer.RenderMaterialIndex = materialIndex; } +#if RHINO_8 + // Section style + if (ToSectionStyle() is SectionStyle sectionStyle) + { + var material = Material; + if (!material.IsEmpty) + { + sectionStyle.HatchPatternColor = material.CutForegroundPatternColor ?? System.Drawing.Color.Black; + if (material.CutForegroundPattern?.BakeElement(idMap, overwrite: false, doc, null, out var patternId) is true) + sectionStyle.HatchIndex = doc.HatchPatterns.FindId(patternId).Index; + + if (material.CutBackgroundPattern.Value?.GetFillPattern()?.IsSolidFill is true) + { + sectionStyle.BackgroundFillColor = material.CutBackgroundPatternColor ?? System.Drawing.Color.White; + sectionStyle.BackgroundFillMode = SectionBackgroundFillMode.SolidColor; + } + else + { + sectionStyle.BackgroundFillMode = SectionBackgroundFillMode.Viewport; + } + } + + layer.SetCustomSectionStyle(sectionStyle); + } + else if (layer.GetCustomSectionStyle() is object) + { + layer.RemoveCustomSectionStyle(); + } +#endif + // Some hardcoded tweaks… switch (Id.ToBuiltInCategory()) { @@ -409,6 +463,7 @@ out Guid guid case ARDB.BuiltInCategory.OST_Levels: case ARDB.BuiltInCategory.OST_Grids: + case ARDB.BuiltInCategory.OST_GridChains: layer.Color = System.Drawing.Color.FromArgb(35, layer.Color); layer.IsLocked = true; break; @@ -420,12 +475,8 @@ out Guid guid #endif break; - case ARDB.BuiltInCategory.OST_GridChains: - layer.Color = System.Drawing.Color.FromArgb(35, layer.Color); - break; case ARDB.BuiltInCategory.OST_LightingFixtureSource: - layer.Color = System.Drawing.Color.FromArgb(35, layer.Color); layer.IsVisible = false; break; } @@ -434,31 +485,59 @@ out Guid guid else if (overwrite) doc.Layers.Modify(layer, index, true); } - idMap.Add(Id, guid = layer.Id); - return true; + if (layer is object) + { + idMap.Add(Id, guid = layer.Id); + return true; + } } - else + + guid = default; + return false; + } + #endregion + + #region ModelContent + private IEnumerable GetElementPath() + { + if (APIObject is ARDB.Category category) { - var index = doc.Layers.FindByFullPath(RootLayerName, -1); - if (index < 0) + var parent = Parent; + if (parent is object) + { + foreach (var token in parent.GetElementPath()) + yield return token; + } + else { - var layer = Layer.GetDefaultLayerProperties(); + yield return "Revit"; + + if (category.Id.TryGetBuiltInCategory(out var bic) && bic != ARDB.BuiltInCategory.OST_ImportObjectStyles) { - layer.Name = RootLayerName; + if (category.IsTagCategory) + { + yield return "Tags"; + } + else if (Types.CategoryType.NamedValues.TryGetValue((int) category.CategoryType, out var typeName)) + { + yield return typeName; + } + else + { + yield return "~"; + } } - index = doc.Layers.Add(layer); + else yield return "Imports"; } - guid = doc.Layers[index].Id; - return true; + if (category.Id.IsBuiltInId() || parent is object) + yield return Nomen; + else + yield return $"<{Nomen}>"; } } - #endregion - #region ModelContent - protected override string ElementPath => Parent is Category parent ? - $"{CategoryType}::{parent.Nomen}::{Nomen}" : - $"{CategoryType}::{Nomen}"; + protected override string ElementPath => string.Join("::", GetElementPath()); #if RHINO_8 internal ModelContent ToModelContent(IDictionary idMap) @@ -472,8 +551,8 @@ internal ModelContent ToModelContent(IDictionary i // Path { - attributes.Path = $"Revit::{ElementPath}"; - }; + attributes.Path = ElementPath; + } // Tags { @@ -490,12 +569,6 @@ internal ModelContent ToModelContent(IDictionary i attributes.Linetype = ProjectionLinePattern?.ToModelContent(idMap) as ModelLinetype ?? ModelLinetype.Unset; } - // LineColor - { - var lineColor = category.LineColor.ToColor(); - attributes.DraftingColor = lineColor.IsEmpty ? System.Drawing.Color.Black : lineColor; - } - // LineWeight { attributes.LineWeight = category.ToBuiltInCategory() == ARDB.BuiltInCategory.OST_InvisibleLines ? @@ -503,19 +576,24 @@ internal ModelContent ToModelContent(IDictionary i ToLineWeight(ProjectionLineWeight); } - // Color + // LineColor { - var displayColor = category.CategoryType != ARDB.CategoryType.Model || - category.Root().ToBuiltInCategory() == ARDB.BuiltInCategory.OST_Lines ? - (System.Drawing.Color) attributes.DraftingColor : - new Material(category.Material).ObjectColor; + var lineColor = category.LineColor.ToColor(); + attributes.DraftingColor = lineColor.IsEmpty ? System.Drawing.Color.Black : lineColor; + } - attributes.DisplayColor = displayColor.IsEmpty ? System.Drawing.Color.FromArgb(0x7F, 0x7F, 0x7F) : displayColor; + // Color + { + attributes.DisplayColor = category.Material.ToShadingMaterial(out var _, out var _); } // Material + if (category.CategoryType != ARDB.CategoryType.Annotation) { - attributes.Material = Material?.ToModelContent(idMap) as ModelRenderMaterial; + var material = Material; + { + attributes.Material = material.ToModelContent(idMap) as ModelRenderMaterial; + } } // Some hardcoded tweaks… @@ -527,12 +605,17 @@ internal ModelContent ToModelContent(IDictionary i case ARDB.BuiltInCategory.OST_Levels: case ARDB.BuiltInCategory.OST_Grids: + case ARDB.BuiltInCategory.OST_GridChains: attributes.DisplayColor = System.Drawing.Color.FromArgb(35, attributes.DisplayColor.Value); attributes.Locked = true; break; + case ARDB.BuiltInCategory.OST_VolumeOfInterest: + attributes.LineWeight = -1.0; + attributes.HiddenOnNewDetail = true; + break; + case ARDB.BuiltInCategory.OST_LightingFixtureSource: - attributes.DisplayColor = System.Drawing.Color.FromArgb(35, attributes.DisplayColor.Value); attributes.Hidden = true; break; } @@ -543,6 +626,27 @@ internal ModelContent ToModelContent(IDictionary i return null; } + + private SectionStyle ToSectionStyle() + { + if (APIObject is ARDB.Category category && category.GetGraphicsStyle(ARDB.GraphicsStyleType.Cut) is object) + { + var style = new SectionStyle(); + + var linetype = CutLinePattern?.ToLinetype(); + { + if (linetype is null) { linetype = new Linetype(); linetype.SetSegments(new double[] { 1.0 }); } + linetype.Name = $"{Nomen} [cut]"; + linetype.WidthUnits = Rhino.UnitSystem.Millimeters; + linetype.Width = ToLineWeight(CutLineWeight); + style.SetBoundaryLinetype(linetype); + } + + return style; + } + + return null; + } #endif #endregion diff --git a/src/RhinoInside.Revit/Convert/Geometry/GeometryDecoder.cs b/src/RhinoInside.Revit/Convert/Geometry/GeometryDecoder.cs index c585a9da4..ae038d6f9 100755 --- a/src/RhinoInside.Revit/Convert/Geometry/GeometryDecoder.cs +++ b/src/RhinoInside.Revit/Convert/Geometry/GeometryDecoder.cs @@ -1668,6 +1668,8 @@ internal static void UpdateGraphicAttributes(ARDB.GeometryObject geometryObject) else if (geometryObject is ARDB.GeometryElement geometry) { context.Material = geometry.MaterialElement; + if (element is ARDB.ElementType) + return; } else if (geometryObject is ARDB.Solid solid) { @@ -1732,8 +1734,12 @@ internal static IEnumerable ToGeometryBaseMany(this ARDB.GeometryO yield break; case ARDB.GeometryInstance instance: - foreach (var g in instance.GetInstanceGeometry().ToGeometryBaseMany(predicate)) + var transform = instance.Transform.ToTransform(); + foreach (var g in instance.SymbolGeometry.ToGeometryBaseMany(predicate)) + { + g.Transform(transform); yield return g; + } yield break; case ARDB.Mesh mesh: diff --git a/src/RhinoInside.Revit/Convert/Render/RenderMaterialConverter.cs b/src/RhinoInside.Revit/Convert/Render/RenderMaterialConverter.cs index de168bc48..278f295f3 100755 --- a/src/RhinoInside.Revit/Convert/Render/RenderMaterialConverter.cs +++ b/src/RhinoInside.Revit/Convert/Render/RenderMaterialConverter.cs @@ -17,7 +17,6 @@ namespace RhinoInside.Revit.Convert.Render { using Numerical; - using Convert.Geometry; using Convert.System.Drawing; using Convert.Units; using External.DB.Extensions; @@ -91,7 +90,8 @@ public static class RenderMaterialConverter internal static RenderMaterial ToRenderMaterial(this ARDB.AppearanceAssetElement appearanceAssetElement, RhinoDoc rhinoDoc) { var renderMaterial = RenderMaterial.CreateBasicMaterial(Rhino.DocObjects.Material.DefaultMaterial, rhinoDoc); - renderMaterial.Name = appearanceAssetElement.Name; + renderMaterial.Name = $"Appearance Assets::{appearanceAssetElement.Name}"; + renderMaterial.Hidden = true; #if REVIT_2018 using (var asset = appearanceAssetElement.GetRenderingAsset()) @@ -175,7 +175,7 @@ public static RenderMaterial ToRenderMaterial(this ARDB.Material material, Rhino #endif { renderMaterial.Fields.Set(RenderMaterial.BasicMaterialParameterNames.Diffuse, material.Color.ToColor()); - renderMaterial.Fields.Set(RenderMaterial.BasicMaterialParameterNames.Shine, material.Shininess / 128.0 * Rhino.DocObjects.Material.MaxShine); + renderMaterial.Fields.Set(RenderMaterial.BasicMaterialParameterNames.Shine, material.Shininess / 128.0); renderMaterial.Fields.Set(RenderMaterial.BasicMaterialParameterNames.Reflectivity, 1.0 / Math.Exp((1.0 - (material.Smoothness / 100.0)) * 10)); renderMaterial.Fields.Set(RenderMaterial.BasicMaterialParameterNames.Transparency, material.Transparency / 100.0); } @@ -183,13 +183,39 @@ public static RenderMaterial ToRenderMaterial(this ARDB.Material material, Rhino return renderMaterial; } + internal static SD.Color ToShadingMaterial(this ARDB.Material material, out double shininess, out double smoothness) + { + if (material is null) + { + shininess = 0.5; + smoothness = 0.0; + return SD.Color.FromArgb(0x7F, 0x7F, 0x7F); + } + else + { + shininess = Math.Round(material.Shininess / 128.0); + smoothness = Math.Round(material.Smoothness / 100.0); + return SD.Color.FromArgb + ( + byte.MaxValue - (int) Math.Round(material.Transparency * 2.55), + material.Color.ToColor() + ); + } + } + #if REVIT_2018 + static double NormalizedChildSlotAmount(RenderContent renderContent, string slotName) + { + return (double) (((float) renderContent.ChildSlotAmount(slotName)) - 0.01f) * 0.01f; + } + class BasicMaterialParameters { public RenderMaterial.PreviewGeometryType PreviewGeometryType = RenderMaterial.PreviewGeometryType.Scene; public Color4f Ambient = Color4f.Black; public Color4f Diffuse = Color4f.White; + public Color4f? Tint = default; public double Shine = 0.0; public Color4f Specular = Color4f.White; @@ -240,6 +266,7 @@ static SimulatedTexture ToSimulatedTexture(Asset asset) if (asset.Name == "UnifiedBitmapSchema") return GetUnifiedBitmapSchemaTexture(asset); if (asset.Name == "BumpMapSchema") return GetBumpMapSchemaTexture(asset); + if (asset.Name == "CheckerSchema") return GetCheckerSchemaTexture(asset); else Debug.WriteLine($"Unimplemented Texture Schema: {asset.Name}"); return default; @@ -403,6 +430,52 @@ static SimulatedProceduralTexture GetBumpMapSchemaTexture(Asset asset) return null; } + static SimulatedProceduralTexture GetCheckerSchemaTexture(Asset asset) + { + var activeModelScale = UnitScale.GetModelScale(RhinoDoc.ActiveDoc); + + var offset = Rhino.Geometry.Vector2d.Zero; + if (asset.FindByName(Checker.TextureRealWorldOffsetX) is AssetPropertyDistance offsetX) + offset.X = ARDB.UnitUtils.Convert(offsetX.Value, offsetX.GetUnitTypeId(), DBXS.UnitType.Meters) / activeModelScale; + if (asset.FindByName(Checker.TextureRealWorldOffsetY) is AssetPropertyDistance offsetY) + offset.Y = ARDB.UnitUtils.Convert(offsetY.Value, offsetY.GetUnitTypeId(), DBXS.UnitType.Meters) / activeModelScale; + + var repeat = new Rhino.Geometry.Vector2d(1.0, 1.0); + if (asset.FindByName(Checker.TextureRealWorldScaleX) is AssetPropertyDistance scaleX) + repeat.X = activeModelScale / ARDB.UnitUtils.Convert(scaleX.Value, scaleX.GetUnitTypeId(), DBXS.UnitType.Meters); + if (asset.FindByName(Checker.TextureRealWorldScaleY) is AssetPropertyDistance scaleY) + repeat.Y = activeModelScale / ARDB.UnitUtils.Convert(scaleY.Value, scaleY.GetUnitTypeId(), DBXS.UnitType.Meters); + + var color_one = Color4f.Black; + if (asset.FindByName(Checker.CheckerColor1) is AssetPropertyDoubleArray4d color1) + color_one = ToColor4f(color1); + + var color_two = Color4f.White; + if (asset.FindByName(Checker.CheckerColor2) is AssetPropertyDoubleArray4d color2) + color_two = ToColor4f(color2); + + var texture = new SimulatedProceduralTexture(ContentUuids.Texture2DCheckerTextureType) + { + ProjectionMode = SimulatedTexture.ProjectionModes.WcsBox, + Fields = + { + { "color-one", color_one }, + { "color-two", color_two } + } + }; + + if (asset.FindByName(Checker.TextureURepeat) is AssetPropertyBoolean uRepeat && + asset.FindByName(Checker.TextureVRepeat) is AssetPropertyBoolean vRepeat) + texture.Repeating = uRepeat.Value | vRepeat.Value; + + if (asset.FindByName(Checker.TextureWAngle) is AssetPropertyDouble angle) + texture.Rotation = RhinoMath.ToRadians(angle.Value); + + texture.Offset = offset; + texture.Repeat = repeat; + + return texture; + } static SimulatedTexture ToSimulatedTexture(string path) { return new SimulatedTexture(RhinoDoc.ActiveDoc) @@ -450,10 +523,60 @@ internal static void SimulateRenderingAsset(this RenderMaterial material, Asset SetChildSlot(material, RenderMaterial.StandardChildSlots.Bump, materialParams.BumpTexture, materialParams.BumpTextureAmount, doc); SetChildSlot(material, RenderMaterial.StandardChildSlots.Transparency, materialParams.OpacityTexture, materialParams.OpacityTextureAmount, doc); SetChildSlot(material, RenderMaterial.StandardChildSlots.Environment, materialParams.EnvironmentTexture, materialParams.EnvironmentTextureAmount, doc); + + TintMaterial(material, materialParams.Tint); } else Debug.WriteLine($"Unimplemented Material Schema: {asset.Name}"); } +#if RHINO_8 + static Guid MultiplyTextureType = ContentUuids.MultiplyTextureType; + static Guid SingleColorTextureType = ContentUuids.SingleColorTextureType; +#else + static readonly Guid MultiplyTextureType = new Guid("{95BF2B4A-C79B-48E8-97D0-2584F2E8E52B}"); + static readonly Guid SingleColorTextureType = new Guid("{B9368B92-9F02-45FB-B6CF-095EF8463550}"); +#endif + + static void TintMaterial(RenderMaterial material, Color4f? tintColor) + { + if (material.TextureChildSlotName(RenderMaterial.StandardChildSlots.Diffuse) is string diffuseSlot) + { + var diffuse = tintColor.HasValue ? + RenderContentType.NewContentFromTypeId(MultiplyTextureType) as RenderTexture: + RenderContentType.NewContentFromTypeId(SingleColorTextureType) as RenderTexture; + + diffuse.Hidden = true; + diffuse.Name = $"{material.Name} Color"; + diffuse.Fields.Set("color-one", material.Fields.GetField(RenderMaterial.BasicMaterialParameterNames.Diffuse).GetValue()); + + if (material.FindChild(diffuseSlot) is RenderTexture previousDiffuse) + { + diffuse.SetProjectionMode(previousDiffuse.GetProjectionMode(), RenderContent.ChangeContexts.Program); + diffuse.SetProjectionMode(previousDiffuse.GetProjectionMode(), RenderContent.ChangeContexts.Program); + diffuse.SetMappingChannel(previousDiffuse.GetMappingChannel(), RenderContent.ChangeContexts.Program); + diffuse.SetWrapType(TextureWrapType.Clamped, RenderContent.ChangeContexts.Program); + diffuse.SetOffset(previousDiffuse.GetOffset(), RenderContent.ChangeContexts.Program); + diffuse.SetRepeat(previousDiffuse.GetRepeat(), RenderContent.ChangeContexts.Program); + diffuse.SetRotation(previousDiffuse.GetRotation(), RenderContent.ChangeContexts.Program); + + diffuse.SetChild(previousDiffuse.MakeCopy(), "color-one"); + diffuse.SetChildSlotAmount("color-one", material.ChildSlotAmount(diffuseSlot), RenderContent.ChangeContexts.Program); + diffuse.SetChildSlotOn("color-one", material.ChildSlotOn(diffuseSlot), RenderContent.ChangeContexts.Program); + } + + if (tintColor.HasValue) + { + diffuse.Fields.Set("color-two", tintColor.Value); + diffuse.SetChildSlotAmount("color-two", 100.0, RenderContent.ChangeContexts.Program); + diffuse.SetChildSlotOn("color-two", true, RenderContent.ChangeContexts.Program); + } + + material.SetChild(diffuse, diffuseSlot); + material.SetChildSlotAmount(diffuseSlot, 100.0, RenderContent.ChangeContexts.Program); + material.SetChildSlotOn(diffuseSlot, true, RenderContent.ChangeContexts.Program); + } + } + static void SetFieldValues(Rhino.Render.Fields.FieldDictionary fields, Dictionary values) { foreach (var field in values) @@ -555,24 +678,20 @@ static bool TryGetBasicMaterialParameters(Asset asset, out BasicMaterialParamete static void GetGenericSchemaParameters(Asset asset, ref BasicMaterialParameters material) { + var metal = (asset.FindByName(Generic.GenericIsMetal) is AssetPropertyBoolean isMetal && isMetal.Value); + if (asset.FindByName(Generic.GenericDiffuse) is AssetPropertyDoubleArray4d diffuse) { material.Diffuse = ToColor4f(diffuse); material.DiffuseTexture = ToSimulatedTexture(diffuse.GetSingleConnectedAsset()); if (asset.FindByName(Generic.GenericDiffuseImageFade) is AssetPropertyDouble diffuseAmount) material.DiffuseTextureAmount = diffuseAmount.Value; + } - if (asset.FindByName(Generic.CommonTintToggle) is AssetPropertyBoolean tintToggle && tintToggle.Value) - { - if (asset.FindByName(Generic.CommonTintColor) is AssetPropertyDoubleArray4d tint) - { - var tintColor = ToColor4f(tint); - material.Diffuse = new Color4f(material.Diffuse.R * tintColor.R, material.Diffuse.G * tintColor.G, material.Diffuse.B * tintColor.B, material.Diffuse.A * tintColor.A); - } - } - - if (asset.FindByName(Generic.GenericIsMetal) is AssetPropertyBoolean isMetal && isMetal.Value) - material.ReflectivityColor = material.Diffuse; + if (asset.FindByName(Generic.CommonTintToggle) is AssetPropertyBoolean tintToggle && tintToggle.Value) + { + if (asset.FindByName(Generic.CommonTintColor) is AssetPropertyDoubleArray4d tint) + material.Tint = ToColor4f(tint); } if (asset.FindByName(Generic.GenericBumpMap) is AssetPropertyDoubleArray4d bumpMap) @@ -592,6 +711,7 @@ static void GetGenericSchemaParameters(Asset asset, ref BasicMaterialParameters if (asset.FindByName(Generic.GenericTransparency) is AssetPropertyDouble transparency) { material.Transparency = transparency.Value; + material.TransparencyColor = material.Diffuse; // TODO : Build a Transparency Texture. //material.OpacityTexture = ToSimulatedTexture(transparency.GetSingleConnectedAsset()); @@ -604,7 +724,7 @@ static void GetGenericSchemaParameters(Asset asset, ref BasicMaterialParameters material.Ior = ior.Value; if (asset.FindByName(Generic.GenericGlossiness) is AssetPropertyDouble glossiness) - material.Reflectivity = glossiness.Value; + material.PolishAmount = glossiness.Value; if (asset.FindByName(Generic.GenericSelfIllumLuminance) is AssetPropertyDouble luminance) { @@ -619,14 +739,20 @@ static void GetGenericSchemaParameters(Asset asset, ref BasicMaterialParameters } } - if (asset.FindByName(Generic.GenericReflectivityAt0deg) is AssetPropertyDouble refelectivity0) - material.PolishAmount = refelectivity0.Value; + if (asset.FindByName(Generic.GenericReflectivityAt0deg) is AssetPropertyDouble reflectivity0) + { + material.Reflectivity = RhinoMath.Clamp(reflectivity0.Value, 0.0, 1.0); ; + material.ReflectivityColor = metal ? material.Diffuse : Color4f.White; + } if (asset.FindByName(Generic.GenericReflectivityAt90deg) is AssetPropertyDouble reflectivity90) - material.Shine = reflectivity90.Value; + { + material.Shine = RhinoMath.Clamp(reflectivity90.Value, 0.0, 1.0); + material.Specular = metal ? material.Diffuse : Color4f.White; + } if (asset.FindByName(Generic.GenericRefractionTranslucencyWeight) is AssetPropertyDouble refractionTranslucencyWeight) - material.ClarityAmount = refractionTranslucencyWeight.Value; + material.ClarityAmount = 1.0 - refractionTranslucencyWeight.Value; } static void GetGlazingSchemaParameters(Asset asset, ref BasicMaterialParameters material) @@ -635,12 +761,12 @@ static void GetGlazingSchemaParameters(Asset asset, ref BasicMaterialParameters { switch ((GlazingTransmittanceColorType) transmittance.Value) { - case GlazingTransmittanceColorType.Clear: material.TransparencyColor = new Color4f(0.858f, 0.893f, 0.879f, 1.0f); break; - case GlazingTransmittanceColorType.Green: material.TransparencyColor = new Color4f(0.676f, 0.797f, 0.737f, 1.0f); break; - case GlazingTransmittanceColorType.Gray: material.TransparencyColor = new Color4f(0.451f, 0.449f, 0.472f, 1.0f); break; - case GlazingTransmittanceColorType.Blue: material.TransparencyColor = new Color4f(0.367f, 0.514f, 0.651f, 1.0f); break; - case GlazingTransmittanceColorType.Bluegreen: material.TransparencyColor = new Color4f(0.654f, 0.788f, 0.772f, 1.0f); break; - case GlazingTransmittanceColorType.Bronze: material.TransparencyColor = new Color4f(0.583f, 0.516f, 0.467f, 1.0f); break; + case GlazingTransmittanceColorType.Clear: material.TransparencyColor = new Color4f(236 / 255f, 240 / 255f, 239 / 255f, 1.0f); break; + case GlazingTransmittanceColorType.Green: material.TransparencyColor = new Color4f(209 / 255f, 227 / 255f, 218 / 255f, 1.0f); break; + case GlazingTransmittanceColorType.Gray: material.TransparencyColor = new Color4f(171 / 255f, 170 / 255f, 175 / 255f, 1.0f); break; + case GlazingTransmittanceColorType.Blue: material.TransparencyColor = new Color4f(154 / 255f, 182 / 255f, 205 / 255f, 1.0f); break; + case GlazingTransmittanceColorType.Bluegreen: material.TransparencyColor = new Color4f(206 / 255f, 226 / 255f, 224 / 255f, 1.0f); break; + case GlazingTransmittanceColorType.Bronze: material.TransparencyColor = new Color4f(194 / 255f, 183 / 255f, 174 / 255f, 1.0f); break; case GlazingTransmittanceColorType.Custom: if (asset.FindByName(Glazing.GlazingTransmittanceMap) is AssetPropertyDoubleArray4d transmittanceCustomColor) { @@ -652,15 +778,12 @@ static void GetGlazingSchemaParameters(Asset asset, ref BasicMaterialParameters } material.Diffuse = material.TransparencyColor; - material.Transparency = 0.9; + material.Transparency = 1.0; if (asset.FindByName(Glazing.CommonTintToggle) is AssetPropertyBoolean tintToggle && tintToggle.Value) { if (asset.FindByName(Glazing.CommonTintColor) is AssetPropertyDoubleArray4d tint) - { - var tintColor = ToColor4f(tint); - material.Diffuse = new Color4f(material.Diffuse.R * tintColor.R, material.Diffuse.G * tintColor.G, material.Diffuse.B * tintColor.B, material.Diffuse.A * tintColor.A); - } + material.Tint = ToColor4f(tint); } material.Ior = 1.52; @@ -670,6 +793,7 @@ static void GetGlazingSchemaParameters(Asset asset, ref BasicMaterialParameters if (asset.FindByName(Glazing.GlazingReflectance) is AssetPropertyDouble refelectance) material.Reflectivity = refelectance.Value; + material.FresnelEnabled = true; material.PolishAmount = 1.0; material.ClarityAmount = 1.0; } @@ -702,10 +826,7 @@ static void GetSolidGlassSchemaParameters(Asset asset, ref BasicMaterialParamete if (asset.FindByName(SolidGlass.CommonTintToggle) is AssetPropertyBoolean tintToggle && tintToggle.Value) { if (asset.FindByName(SolidGlass.CommonTintColor) is AssetPropertyDoubleArray4d tint) - { - var tintColor = ToColor4f(tint); - material.Diffuse = new Color4f(material.Diffuse.R * tintColor.R, material.Diffuse.G * tintColor.G, material.Diffuse.B * tintColor.B, material.Diffuse.A * tintColor.A); - } + material.Tint = ToColor4f(tint); } if (asset.FindByName(SolidGlass.SolidglassRefractionIor) is AssetPropertyDouble ior) @@ -748,15 +869,12 @@ static void GetConcreteSchemaParameters(Asset asset, ref BasicMaterialParameters { material.Diffuse = ToColor4f(diffuse); material.DiffuseTexture = ToSimulatedTexture(diffuse.GetSingleConnectedAsset()); + } - if (asset.FindByName(Concrete.CommonTintToggle) is AssetPropertyBoolean tintToggle && tintToggle.Value) - { - if (asset.FindByName(Concrete.CommonTintColor) is AssetPropertyDoubleArray4d tint) - { - var tintColor = ToColor4f(tint); - material.Diffuse = new Color4f(material.Diffuse.R * tintColor.R, material.Diffuse.G * tintColor.G, material.Diffuse.B * tintColor.B, material.Diffuse.A * tintColor.A); - } - } + if (asset.FindByName(Concrete.CommonTintToggle) is AssetPropertyBoolean tintToggle && tintToggle.Value) + { + if (asset.FindByName(Concrete.CommonTintColor) is AssetPropertyDoubleArray4d tint) + material.Tint = ToColor4f(tint); } if (asset.FindByName(Concrete.ConcreteSealant) is AssetPropertyInteger sealant) @@ -813,17 +931,15 @@ static void GetStoneSchemaParameters(Asset asset, ref BasicMaterialParameters ma if (asset.FindByName(Stone.StoneColor) is AssetPropertyReference diffuse) { material.DiffuseTexture = ToSimulatedTexture(diffuse.GetSingleConnectedAsset()); + } - if (asset.FindByName(Stone.CommonTintToggle) is AssetPropertyBoolean tintToggle && tintToggle.Value) - { - if (asset.FindByName(Stone.CommonTintColor) is AssetPropertyDoubleArray4d tint) - { - var tintColor = ToColor4f(tint); - material.Diffuse = new Color4f(material.Diffuse.R * tintColor.R, material.Diffuse.G * tintColor.G, material.Diffuse.B * tintColor.B, material.Diffuse.A * tintColor.A); - } - } + if (asset.FindByName(Stone.CommonTintToggle) is AssetPropertyBoolean tintToggle && tintToggle.Value) + { + if (asset.FindByName(Stone.CommonTintColor) is AssetPropertyDoubleArray4d tint) + material.Tint = ToColor4f(tint); } + if (asset.FindByName(Stone.StoneApplication) is AssetPropertyInteger application) { switch ((StoneApplicationType) application.Value) @@ -902,7 +1018,7 @@ static void GetMetalSchemaParameters(Asset asset, ref BasicMaterialParameters ma material.Diffuse = ToColor4f(metalColor); material.DiffuseTexture = ToSimulatedTexture(metalColor.GetSingleConnectedAsset()); } - metalFinishType = MetalFinishType.Polished; + metalFinishType = MetalFinishType.Brushed; break; case MetalType.Chrome: material.Diffuse = new Color4f(SD.Color.FromArgb(244, 244, 244)); break; case MetalType.Copper: material.Diffuse = new Color4f(SD.Color.FromArgb(187, 80, 46)); break; @@ -919,10 +1035,7 @@ static void GetMetalSchemaParameters(Asset asset, ref BasicMaterialParameters ma if (asset.FindByName(Metal.CommonTintToggle) is AssetPropertyBoolean tintToggle && tintToggle.Value) { if (asset.FindByName(Metal.CommonTintColor) is AssetPropertyDoubleArray4d tint) - { - var tintColor = ToColor4f(tint); - material.Diffuse = new Color4f(material.Diffuse.R * tintColor.R, material.Diffuse.G * tintColor.G, material.Diffuse.B * tintColor.B, material.Diffuse.A * tintColor.A); - } + material.Tint = ToColor4f(tint); } material.ReflectivityColor = material.Diffuse; @@ -961,15 +1074,12 @@ static void GetMetallicPaintSchemaParameters(Asset asset, ref BasicMaterialParam { material.Diffuse = ToColor4f(diffuse); material.DiffuseTexture = ToSimulatedTexture(diffuse.GetSingleConnectedAsset()); + } - if (asset.FindByName(MetallicPaint.CommonTintToggle) is AssetPropertyBoolean tintToggle && tintToggle.Value) - { - if (asset.FindByName(MetallicPaint.CommonTintColor) is AssetPropertyDoubleArray4d tint) - { - var tintColor = ToColor4f(tint); - material.Diffuse = new Color4f(material.Diffuse.R * tintColor.R, material.Diffuse.G * tintColor.G, material.Diffuse.B * tintColor.B, material.Diffuse.A * tintColor.A); - } - } + if (asset.FindByName(MetallicPaint.CommonTintToggle) is AssetPropertyBoolean tintToggle && tintToggle.Value) + { + if (asset.FindByName(MetallicPaint.CommonTintColor) is AssetPropertyDoubleArray4d tint) + material.Tint = ToColor4f(tint); } if (asset.FindByName(MetallicPaint.MetallicpaintPearlColor) is AssetPropertyDoubleArray4d specular) @@ -1007,8 +1117,8 @@ static void GetMetallicPaintSchemaParameters(Asset asset, ref BasicMaterialParam if (asset.FindByName(MetallicPaint.MetallicpaintTopcoatGlossy) is AssetPropertyDouble glossy) glossines = glossy.Value; - if (asset.FindByName(MetallicPaint.MetallicpaintTopcoatFalloff) is AssetPropertyDouble fallof) - angle = fallof.Value; + if (asset.FindByName(MetallicPaint.MetallicpaintTopcoatFalloff) is AssetPropertyDouble falloff) + angle = falloff.Value; break; } } @@ -1031,17 +1141,12 @@ static void GetWallPaintSchemaParameters(Asset asset, ref BasicMaterialParameter { material.Diffuse = ToColor4f(diffuse); material.DiffuseTexture = ToSimulatedTexture(diffuse.GetSingleConnectedAsset()); + } - if (asset.FindByName(WallPaint.CommonTintToggle) is AssetPropertyBoolean tintToggle && tintToggle.Value) - { - if (asset.FindByName(WallPaint.CommonTintColor) is AssetPropertyDoubleArray4d tint) - { - var tintColor = ToColor4f(tint); - material.Diffuse = new Color4f(material.Diffuse.R * tintColor.R, material.Diffuse.G * tintColor.G, material.Diffuse.B * tintColor.B, material.Diffuse.A * tintColor.A); - } - } - - material.ReflectivityColor = material.Diffuse; + if (asset.FindByName(WallPaint.CommonTintToggle) is AssetPropertyBoolean tintToggle && tintToggle.Value) + { + if (asset.FindByName(WallPaint.CommonTintColor) is AssetPropertyDoubleArray4d tint) + material.Tint = ToColor4f(tint); } // TODO: apply some bump texture @@ -1086,17 +1191,11 @@ static void GetHardwoodSchemaParameters(Asset asset, ref BasicMaterialParameters { material.Diffuse = Color4f.White; material.DiffuseTexture = ToSimulatedTexture(hardwoodColor.GetSingleConnectedAsset()); - - if (asset.FindByName(Hardwood.CommonTintToggle) is AssetPropertyBoolean tintToggle && tintToggle.Value) - { - if (asset.FindByName(Hardwood.CommonTintColor) is AssetPropertyDoubleArray4d tint) - { - var tintColor = ToColor4f(tint); - material.Diffuse = new Color4f(material.Diffuse.R * tintColor.R, material.Diffuse.G * tintColor.G, material.Diffuse.B * tintColor.B, material.Diffuse.A * tintColor.A); - } - } - - material.ReflectivityColor = material.Diffuse; + } + if (asset.FindByName(Hardwood.CommonTintToggle) is AssetPropertyBoolean tintToggle && tintToggle.Value) + { + if (asset.FindByName(Hardwood.CommonTintColor) is AssetPropertyDoubleArray4d tint) + material.Tint = ToColor4f(tint); } // TODO: apply some bump texture @@ -1137,16 +1236,12 @@ static void GetCeramicSchemaParameters(Asset asset, ref BasicMaterialParameters material.Diffuse = ToColor4f(diffuse); material.DiffuseTexture = ToSimulatedTexture(diffuse.GetSingleConnectedAsset()); - if (asset.FindByName(Ceramic.CommonTintToggle) is AssetPropertyBoolean tintToggle && tintToggle.Value) - { - if (asset.FindByName(Ceramic.CommonTintColor) is AssetPropertyDoubleArray4d tint) - { - var tintColor = ToColor4f(tint); - material.Diffuse = new Color4f(material.Diffuse.R * tintColor.R, material.Diffuse.G * tintColor.G, material.Diffuse.B * tintColor.B, material.Diffuse.A * tintColor.A); - } - } + } - material.ReflectivityColor = material.Diffuse; + if (asset.FindByName(Ceramic.CommonTintToggle) is AssetPropertyBoolean tintToggle && tintToggle.Value) + { + if (asset.FindByName(Ceramic.CommonTintColor) is AssetPropertyDoubleArray4d tint) + material.Tint = ToColor4f(tint); } double polish = 0.0; @@ -1201,17 +1296,12 @@ static void GetPlasticVinylSchemaParameters(Asset asset, ref BasicMaterialParame { material.Diffuse = ToColor4f(diffuse); material.DiffuseTexture = ToSimulatedTexture(diffuse.GetSingleConnectedAsset()); + } - if (asset.FindByName(PlasticVinyl.CommonTintToggle) is AssetPropertyBoolean tintToggle && tintToggle.Value) - { - if (asset.FindByName(PlasticVinyl.CommonTintColor) is AssetPropertyDoubleArray4d tint) - { - var tintColor = ToColor4f(tint); - material.Diffuse = new Color4f(material.Diffuse.R * tintColor.R, material.Diffuse.G * tintColor.G, material.Diffuse.B * tintColor.B, material.Diffuse.A * tintColor.A); - } - } - - material.ReflectivityColor = material.Diffuse; + if (asset.FindByName(PlasticVinyl.CommonTintToggle) is AssetPropertyBoolean tintToggle && tintToggle.Value) + { + if (asset.FindByName(PlasticVinyl.CommonTintColor) is AssetPropertyDoubleArray4d tint) + material.Tint = ToColor4f(tint); } double polish = 0.0; @@ -1408,10 +1498,7 @@ static void GetWaterSchemaParameters(Asset asset, ref BasicMaterialParameters ma if (asset.FindByName(Water.CommonTintToggle) is AssetPropertyBoolean tintToggle && tintToggle.Value) { if (asset.FindByName(Water.CommonTintColor) is AssetPropertyDoubleArray4d tint) - { - var tintColor = ToColor4f(tint); - material.Diffuse = new Color4f(material.Diffuse.R * tintColor.R, material.Diffuse.G * tintColor.G, material.Diffuse.B * tintColor.B, material.Diffuse.A * tintColor.A); - } + material.Tint = ToColor4f(tint); } material.Shine = material.PolishAmount; @@ -1435,10 +1522,7 @@ static void GetMirrorSchemaParameters(Asset asset, ref BasicMaterialParameters m if (asset.FindByName(Mirror.CommonTintToggle) is AssetPropertyBoolean tintToggle && tintToggle.Value) { if (asset.FindByName(Mirror.CommonTintColor) is AssetPropertyDoubleArray4d tint) - { - var tintColor = ToColor4f(tint); - material.ReflectivityColor = new Color4f(material.Diffuse.R * tintColor.R, material.Diffuse.G * tintColor.G, material.Diffuse.B * tintColor.B, material.Diffuse.A * tintColor.A); - } + material.Tint = ToColor4f(tint); } } @@ -1450,17 +1534,12 @@ static void GetMasonryCMUSchemaParameters(Asset asset, ref BasicMaterialParamete { material.Diffuse = ToColor4f(diffuse); material.DiffuseTexture = ToSimulatedTexture(diffuse.GetSingleConnectedAsset()); + } - if (asset.FindByName(MasonryCMU.CommonTintToggle) is AssetPropertyBoolean tintToggle && tintToggle.Value) - { - if (asset.FindByName(MasonryCMU.CommonTintColor) is AssetPropertyDoubleArray4d tint) - { - var tintColor = ToColor4f(tint); - material.Diffuse = new Color4f(material.Diffuse.R * tintColor.R, material.Diffuse.G * tintColor.G, material.Diffuse.B * tintColor.B, material.Diffuse.A * tintColor.A); - } - } - - material.ReflectivityColor = material.Diffuse; + if (asset.FindByName(MasonryCMU.CommonTintToggle) is AssetPropertyBoolean tintToggle && tintToggle.Value) + { + if (asset.FindByName(MasonryCMU.CommonTintColor) is AssetPropertyDoubleArray4d tint) + material.Tint = ToColor4f(tint); } if (asset.FindByName(MasonryCMU.MasonryCMUPatternMap) is AssetPropertyReference bumpMap) @@ -1654,10 +1733,10 @@ static void GetPrismGlazingSchemaParameters(Asset asset, ref BasicMaterialParame material.OpacityTexture = ToSimulatedTexture(cutout.GetSingleConnectedAsset()); } - if (asset.FindByName(AdvancedGlazing.SurfaceAlbedo) is AssetPropertyDoubleArray4d albeldo) + if (asset.FindByName(AdvancedGlazing.SurfaceAlbedo) is AssetPropertyDoubleArray4d albedo) { material.Reflectivity = 1.0; - material.ReflectivityColor = ToColor4f(albeldo); + material.ReflectivityColor = ToColor4f(albedo); } } #endif @@ -1691,14 +1770,14 @@ internal static void SetProperties(this Asset asset, RenderMaterial material) if (mat.Fields.TryGetValue(Rhino.Render.RenderMaterial.BasicMaterialParameterNames.Ior, out double ior)) asset.SetProperty(Generic.GenericRefractionIndex, ior); - if (mat.Fields.TryGetValue(Rhino.Render.RenderMaterial.BasicMaterialParameterNames.Shine, out double shine)) - asset.SetProperty(Generic.GenericGlossiness, shine); - if (mat.Fields.TryGetValue("polish-amount", out double polish)) - asset.SetProperty(Generic.GenericReflectivityAt0deg, polish * 0.5); + asset.SetProperty(Generic.GenericGlossiness, polish); + + if (mat.Fields.TryGetValue(Rhino.Render.RenderMaterial.BasicMaterialParameterNames.Shine, out double shine)) + asset.SetProperty(Generic.GenericReflectivityAt90deg, shine * 0.5); if (mat.Fields.TryGetValue(Rhino.Render.RenderMaterial.BasicMaterialParameterNames.Reflectivity, out double reflectivity)) - asset.SetProperty(Generic.GenericReflectivityAt90deg, reflectivity * 0.5); + asset.SetProperty(Generic.GenericReflectivityAt0deg, reflectivity * 0.5); if (mat.Fields.TryGetValue(Rhino.Render.RenderMaterial.BasicMaterialParameterNames.Transparency, out double transparency)) { @@ -1720,21 +1799,21 @@ internal static void SetProperties(this Asset asset, RenderMaterial material) if (mat.ChildSlotOn("bitmap-texture")) { asset.SetProperty(Generic.GenericDiffuse, mat.FindChild("bitmap-texture") as RenderTexture); - asset.SetProperty(Generic.GenericDiffuseImageFade, mat.ChildSlotAmount("bitmap-texture") * 0.01); + asset.SetProperty(Generic.GenericDiffuseImageFade, NormalizedChildSlotAmount(mat, "bitmap-texture")); } else asset.SetProperty(Generic.GenericDiffuse, default(RenderTexture)); if (mat.ChildSlotOn("transparency-texture")) { asset.SetProperty(Generic.GenericTransparency, mat.FindChild("transparency-texture") as RenderTexture); - asset.SetProperty(Generic.GenericTransparencyImageFade, mat.ChildSlotAmount("transparency-texture") * 0.01); + asset.SetProperty(Generic.GenericTransparencyImageFade, NormalizedChildSlotAmount(mat, "transparency-texture")); } else asset.SetProperty(Generic.GenericTransparency, default(RenderTexture)); if (mat.ChildSlotOn("bump-texture")) { asset.SetProperty(Generic.GenericBumpMap, mat.FindChild("bump-texture") as RenderTexture); - asset.SetProperty(Generic.GenericBumpAmount, mat.ChildSlotAmount("bump-texture") * 0.01); + asset.SetProperty(Generic.GenericBumpAmount, NormalizedChildSlotAmount(mat, "bump-texture")); } else asset.SetProperty(Generic.GenericBumpMap, default(RenderTexture)); }