7860c44f4e
* Dim/quack lets go (#1275) * Add model ingestion to sharp connectors * correct ingestion message * Progress * grasshopper * GH exception messages * fix GH * file names * revit file name * grasshopper file names * etabs file names * delete tests * tekla maybe * ingestion scope * bad boolean logic * Longer TimeSpan * wip upload pipe * 10s * passthrough ingestion id * happy hack time: prevent ingestion completion this is handled server-side in the processing logic. * add packfile send endpoint detection and routing Route to SendViaPackfile when the server supports the upload-signing endpoint (POST probe, 404 = unsupported) and a continuous traversal builder is registered. * Adds Continuous Traversal Builder Introduces a Continuous Traversal Builder to manage the conversion and processing of Revit elements within a Send Pipeline. --------- Co-authored-by: Jedd Morgan <45512892+JR-Morgan@users.noreply.github.com> * feat(api): DI Refactor for Duck DB + Gergo's API endpoint changes (#1282) * Di * undo accidental change * Feat (duck): dui ingestion updates post upload (#1295) * Pass optional ingestion id to DUI * Make ingestion id null for the SendViaIngestion, see the note :) * feat!: Duckdev progress reporitng (#1296) * Di * throwaway from laptop * Progress reporting * Use matching logger * Revit and revert rhino unpacker progress * more revertion * make pr even cleaner * and this one * fix build issues with other connectors * SDK nuget (#1299) * Bump to 3.14.0-alpha.2 * Feat(duck): grasshopper (#1297) * Duck x Grasshopper - who would win? * Fix registration for new builder * missing imports * return version id grasshopper * Align sync resource to sync --------- Co-authored-by: Jedd Morgan <45512892+JR-Morgan@users.noreply.github.com> * Bump SDK * feat(importer): rhino file importer changes for packfile (#1301) * rhino importer changes * correct deps * Bump SDK * Fix build issues * ditto * Fix build issue * Lower standards * Fix build * feat: duck for acad, civil, navis, tekla, etabs (#1300) * duck: acad, civil, etabs, tekla, navis and bump channels to 10.0.0 * notes * fix conflicts * more conflicts * Ready for testing * fix(duck): Fix send caching (#1302) * potential fix * undo-rhino chnages * fix xml comment * amended comment * revit * Fix build * Aligned converting message * fix: reoccurring object references * Bump sdk and resolve merge conflict issues * Merge pull request #1317 from specklesystems/jrm/importer-tracing feat(otel): Tracing and OTEL changes for Rhino importer * Fix revit linked model progress (#1312) * Revert otel packages * bump SDK * Trace unpacking groups * Align trace context nullability with app * Disable send caching in Navisworks * comments * Update FileimportPayload.cs * fix using directive --------- Co-authored-by: Jedd Morgan <45512892+JR-Morgan@users.noreply.github.com> * Fix merge conflicts --------- Co-authored-by: Dimitrie Stefanescu <didimitrie@gmail.com> Co-authored-by: Oğuzhan Koral <45078678+oguzhankoral@users.noreply.github.com> Co-authored-by: Björn Steinhagen <88777268+bjoernsteinhagen@users.noreply.github.com> Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> Co-authored-by: Sebastian Witt <sebastian.witt@rwth-aachen.de>
204 lines
7.1 KiB
C#
204 lines
7.1 KiB
C#
using Autodesk.AutoCAD.Colors;
|
|
using Autodesk.AutoCAD.DatabaseServices;
|
|
using Autodesk.AutoCAD.GraphicsInterface;
|
|
using Microsoft.Extensions.Logging;
|
|
using Speckle.Connectors.Common.Conversion;
|
|
using Speckle.InterfaceGenerator;
|
|
using Speckle.Objects.Other;
|
|
using Speckle.Sdk;
|
|
using Speckle.Sdk.Common;
|
|
using Speckle.Sdk.Models;
|
|
using Speckle.Sdk.Pipelines.Progress;
|
|
using Material = Autodesk.AutoCAD.DatabaseServices.Material;
|
|
using RenderMaterial = Speckle.Objects.Other.RenderMaterial;
|
|
|
|
namespace Speckle.Connectors.Autocad.HostApp;
|
|
|
|
/// <summary>
|
|
/// Expects to be a scoped dependency for a given operation and helps with layer creation and cleanup.
|
|
/// </summary>
|
|
[GenerateAutoInterface]
|
|
public class AutocadMaterialBaker : IAutocadMaterialBaker
|
|
{
|
|
private readonly ILogger<AutocadMaterialBaker> _logger;
|
|
private readonly AutocadContext _autocadContext;
|
|
private Document Doc => Application.DocumentManager.MdiActiveDocument;
|
|
public Dictionary<string, ObjectId> ObjectMaterialsIdMap { get; } = new();
|
|
|
|
public AutocadMaterialBaker(AutocadContext autocadContext, ILogger<AutocadMaterialBaker> logger)
|
|
{
|
|
_autocadContext = autocadContext;
|
|
_logger = logger;
|
|
}
|
|
|
|
/// <summary>
|
|
/// Try to get material id from original object or its parent (if provided) as fallback).
|
|
/// It covers one-to-many problem, i.e.
|
|
/// - rhino: Brep (material id is extracted into render material proxy objects) -> [Mesh, Mesh, ...] (child objects application ids ARE NOT EXIST in render material proxy objects)
|
|
/// - revit : RevitElement (material IS NOT extracted into render material proxy objects) -> [Mesh, Mesh...] (child objects application ids EXIST in render material proxy objects)
|
|
/// </summary>
|
|
/// <remarks>
|
|
/// This is a question that we need to answer where to handle these cases.
|
|
/// We alsa do reverse search for layer render materials on Revit Receive, and mutating the proxy list accordingly.
|
|
/// These cases are increasing, and need some ideation around it before going more messy.
|
|
/// </remarks>
|
|
public bool TryGetMaterialId(Base originalObject, Base? parentObject, out ObjectId materialId)
|
|
{
|
|
materialId = ObjectId.Null;
|
|
var originalObjectId = originalObject.applicationId ?? originalObject.id.NotNull();
|
|
if (ObjectMaterialsIdMap.TryGetValue(originalObjectId, out ObjectId originalObjectMaterialId))
|
|
{
|
|
materialId = originalObjectMaterialId;
|
|
return true;
|
|
}
|
|
|
|
if (parentObject is null)
|
|
{
|
|
return false;
|
|
}
|
|
|
|
var subObjectId = parentObject.applicationId ?? parentObject.id.NotNull();
|
|
if (ObjectMaterialsIdMap.TryGetValue(subObjectId, out ObjectId subObjectMaterialId))
|
|
{
|
|
materialId = subObjectMaterialId;
|
|
return true;
|
|
}
|
|
|
|
return false;
|
|
}
|
|
|
|
/// <summary>
|
|
/// Removes all materials with a name starting with <paramref name="namePrefix"/> from the active document
|
|
/// </summary>
|
|
/// <param name="namePrefix"></param>
|
|
public void PurgeMaterials(string namePrefix)
|
|
{
|
|
using var transaction = Application.DocumentManager.CurrentDocument.Database.TransactionManager.StartTransaction();
|
|
if (transaction.GetObject(Doc.Database.MaterialDictionaryId, OpenMode.ForWrite) is DBDictionary materialDict)
|
|
{
|
|
foreach (var entry in materialDict)
|
|
{
|
|
try
|
|
{
|
|
if (entry.Key.Contains(namePrefix))
|
|
{
|
|
materialDict.Remove(entry.Value);
|
|
}
|
|
}
|
|
catch (Exception ex) when (!ex.IsFatal())
|
|
{
|
|
_logger.LogError(ex, "Failed to purge a material from the document");
|
|
}
|
|
}
|
|
}
|
|
transaction.Commit();
|
|
}
|
|
|
|
public void ParseAndBakeRenderMaterials(
|
|
IReadOnlyCollection<RenderMaterialProxy> materialProxies,
|
|
string baseLayerPrefix,
|
|
IProgress<CardProgress> onOperationProgressed
|
|
)
|
|
{
|
|
using var transaction = Application.DocumentManager.CurrentDocument.Database.TransactionManager.StartTransaction();
|
|
var materialDict = transaction.GetObject(Doc.Database.MaterialDictionaryId, OpenMode.ForWrite) as DBDictionary;
|
|
|
|
if (materialDict == null)
|
|
{
|
|
// POC: we should report failed conversion here if material dict is not accessible, but it is not linked to a Base source
|
|
transaction.Commit();
|
|
return;
|
|
}
|
|
|
|
var count = 0;
|
|
foreach (RenderMaterialProxy materialProxy in materialProxies)
|
|
{
|
|
onOperationProgressed.Report(new("Converting render materials", (double)++count / materialProxies.Count));
|
|
|
|
// bake render material
|
|
RenderMaterial renderMaterial = materialProxy.value;
|
|
string renderMaterialId = renderMaterial.applicationId ?? renderMaterial.id.NotNull();
|
|
ObjectId materialId = ObjectId.Null;
|
|
|
|
if (!ObjectMaterialsIdMap.TryGetValue(renderMaterialId, out materialId))
|
|
{
|
|
(materialId, ReceiveConversionResult result) = BakeMaterial(
|
|
renderMaterial,
|
|
baseLayerPrefix,
|
|
materialDict,
|
|
transaction
|
|
);
|
|
}
|
|
|
|
if (materialId == ObjectId.Null)
|
|
{
|
|
continue;
|
|
}
|
|
|
|
// parse render material object ids
|
|
foreach (string objectId in materialProxy.objects)
|
|
{
|
|
ObjectMaterialsIdMap[objectId] = materialId;
|
|
}
|
|
}
|
|
|
|
transaction.Commit();
|
|
}
|
|
|
|
private (ObjectId, ReceiveConversionResult) BakeMaterial(
|
|
RenderMaterial renderMaterial,
|
|
string baseLayerPrefix,
|
|
DBDictionary materialDict,
|
|
Transaction tr
|
|
)
|
|
{
|
|
ObjectId materialId = ObjectId.Null;
|
|
|
|
try
|
|
{
|
|
// POC: Currently we're relying on the render material name for identification if it's coming from speckle and from which model; could we do something else?
|
|
// POC: we should assume render materials all have application ids?
|
|
string renderMaterialId = renderMaterial.applicationId ?? renderMaterial.id.NotNull();
|
|
string matName = _autocadContext.RemoveInvalidChars(
|
|
$"{renderMaterial.name}-({renderMaterialId})-{baseLayerPrefix}"
|
|
);
|
|
|
|
MaterialMap map = new();
|
|
MaterialOpacityComponent opacity = new(renderMaterial.opacity, map);
|
|
var systemDiffuse = System.Drawing.Color.FromArgb(renderMaterial.diffuse);
|
|
EntityColor entityDiffuseColor = new(systemDiffuse.R, systemDiffuse.G, systemDiffuse.B);
|
|
MaterialColor diffuseColor = new(Method.Override, 1, entityDiffuseColor);
|
|
MaterialDiffuseComponent diffuse = new(diffuseColor, map);
|
|
|
|
Material mat =
|
|
new()
|
|
{
|
|
Name = matName,
|
|
Opacity = opacity,
|
|
Diffuse = diffuse
|
|
};
|
|
|
|
if (renderMaterial["reflectivity"] is double reflectivity)
|
|
{
|
|
mat.Reflectivity = reflectivity;
|
|
}
|
|
|
|
if (renderMaterial["ior"] is double ior)
|
|
{
|
|
mat.Refraction = new(ior, map);
|
|
}
|
|
|
|
// POC: assumes all materials with this prefix has already been purged from doc
|
|
materialId = materialDict.SetAt(matName, mat);
|
|
tr.AddNewlyCreatedDBObject(mat, true);
|
|
|
|
return (materialId, new(Status.SUCCESS, renderMaterial, matName, "Material"));
|
|
}
|
|
catch (Exception ex) when (!ex.IsFatal())
|
|
{
|
|
_logger.LogError(ex, "Failed to add a material to the document");
|
|
return (materialId, new(Status.ERROR, renderMaterial, null, null, ex));
|
|
}
|
|
}
|
|
}
|