Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
97 changes: 81 additions & 16 deletions src/DynamoRevit/Models/RevitDynamoModel.cs
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,6 @@
using System.Collections.Specialized;
using System.Diagnostics;
using System.Linq;
using System.Runtime.Serialization;
using System.Windows.Forms;
using Autodesk.Revit.DB;
using Autodesk.Revit.DB.Events;
Expand All @@ -21,6 +20,7 @@
using Dynamo.Updates;
using Dynamo.Utilities;
using Greg;
using Newtonsoft.Json;
using ProtoCore;
using Revit.Elements;
using RevitServices.Elements;
Expand Down Expand Up @@ -244,7 +244,7 @@ private RevitDynamoModel(IRevitStartConfiguration configuration) :
/// deleting elements which have been orphaned and exist in trace but were not re-created
/// </summary>
/// <param name="orphanedSerializables"></param>
public override void PostTraceReconciliation(Dictionary<Guid, List<ISerializable>> orphanedSerializables)
public override void PostTraceReconciliation(Dictionary<Guid, List<string>> orphanedSerializables)
{
// because of multiSerialzableIDs some extra logic is
// required to detect if one multiSerializableID is a subset of another, if thats the case we should not delete it.
Expand All @@ -259,6 +259,9 @@ public override void PostTraceReconciliation(Dictionary<Guid, List<ISerializable

//list of UUIDs we will remove from the list of orphans
var toRemove = new List<String>();
//list of stringIDs that we will track to remove. Initially will populate with StringIDs found in any MultipleSerializableId
//or SerializableId object in the trace
var orphanedIds = new List<string>();

//foreach orphaned ID check 2 cases:
//1. an orphaned MultID is totally subset in one of the latest MultIDs
Expand All @@ -267,10 +270,18 @@ public override void PostTraceReconciliation(Dictionary<Guid, List<ISerializable
foreach (var orphan in orphanedSerializables)
{
//if there are no multiSeriializables in the orphan then we can skip this orphan
if (orphan.Value.OfType<MultipleSerializableId>().Count() == 0)
if (orphan.Value.Where(x => x.Contains("StringIDs") && x.Contains("IntIDs")).Count() == 0)
{
continue;
}

//else we need to process those multiSerializableIDs that exist in the orphan
var orphanMultipleSerializableIdObjects = GetAnyMultipleSerializableIDsFromListOfTraceData(orphan.Value);
var orphanStringIDs = orphanMultipleSerializableIdObjects.SelectMany(y => y.StringIDs);

//Add to orphanedIds for later processing
orphanedIds.AddRange(orphanStringIDs);

// Selecting all nodes that are either a DSFunction,
// a DSVarArgFunction or a CodeBlockNodeModel into a list.
var nodeGuids = this.Workspaces.Where(x => x.Guid == orphan.Key).First().Nodes.Where((n) =>
Expand All @@ -289,27 +300,23 @@ public override void PostTraceReconciliation(Dictionary<Guid, List<ISerializable
foreach (var cs in kvp.Value)
{
var currentSerializables = cs.TraceData.SelectMany(td => td.RecursiveGetNestedData());
var currentStringIds = currentSerializables.OfType<MultipleSerializableId>().SelectMany(x => x.StringIDs).ToList();

var currentMultipleSerializableIdObject = GetAnyMultipleSerializableIDsFromListOfTraceData(currentSerializables);

var currentStringIds = currentMultipleSerializableIdObject.SelectMany(x => x.StringIDs).ToList();
//if the orphaned serializable exists in the currentTraceData as as subset in a MultiSerializableID
toRemove.AddRange(orphan.Value.OfType<MultipleSerializableId>().Where(x => currentSerializables.OfType<MultipleSerializableId>().Any(y => x.isSubset(y))).SelectMany(x=>x.StringIDs).ToList());
toRemove.AddRange(orphanMultipleSerializableIdObjects.Where(x => currentMultipleSerializableIdObject.Any(y => x.isSubset(y))).SelectMany(x=>x.StringIDs).ToList());
//Or if one of the callsites traceData is subset in an orphan
toRemove.AddRange(currentStringIds.Intersect(orphan.Value.OfType<MultipleSerializableId>().SelectMany(y => y.StringIDs)).ToList());
toRemove.AddRange(currentStringIds.Intersect(orphanStringIDs).ToList());
//then remove it from the orphanList so we do not delete it later

}
}
}

var orphanedIds = new List<string>();
var serializables =
orphanedSerializables
.SelectMany(kvp => kvp.Value)
.Where(x => x is ISerializable);

orphanedIds.AddRange(serializables.Where(x => x is SerializableId).
Cast<SerializableId>().Select(sid => sid.StringID));
orphanedIds.AddRange(serializables.Where(x => x is MultipleSerializableId).
Cast<MultipleSerializableId>().SelectMany(sid => sid.StringIDs));
//Now we find and add any StringIDs from SerializableID objects pressent in the orphan cachne
var stringIDsFromSerializeIDs = GetAnyStringIDsFromSerializableIDsPressentInOrhpanDictionary(orphanedSerializables);
orphanedIds.AddRange(stringIDsFromSerializeIDs);

toRemove.ForEach(x => orphanedIds.Remove(x));
//the orphansIdsList is now free of elements that are subsets of newly created elements or Items that contain newly created elements
Expand All @@ -332,6 +339,64 @@ public override void PostTraceReconciliation(Dictionary<Guid, List<ISerializable
}
}

private List<MultipleSerializableId> GetAnyMultipleSerializableIDsFromListOfTraceData(IEnumerable<string> currentSerializables)
{
var anyMultipleSerializableId = new List<MultipleSerializableId>();
if (currentSerializables == null)
return anyMultipleSerializableId;

foreach(var currentSerializable in currentSerializables)
{
if(currentSerializable == null) continue;

MultipleSerializableId multi = null;
try
{
multi = JsonConvert.DeserializeObject<MultipleSerializableId>(currentSerializable);
}
catch
{
//do nothing
}

if (multi != null)
anyMultipleSerializableId.Add(multi);
}

return anyMultipleSerializableId;
}

private List<string> GetAnyStringIDsFromSerializableIDsPressentInOrhpanDictionary(Dictionary<Guid,List<string>> orphanedSerializables)
{
var allStringIDs = new List<string>();

if (orphanedSerializables == null)
return allStringIDs;

foreach (var keyValuePair in orphanedSerializables)
{
foreach (var serializableString in keyValuePair.Value)
{
if (serializableString == null) continue;

SerializableId serializableObj = null;
try
{
serializableObj = JsonConvert.DeserializeObject<SerializableId>(serializableString);
}
catch
{
//do nothing
}

if (serializableObj != null)
allStringIDs.Add(serializableObj.StringID);
}
}

return allStringIDs;
}

private static void DeleteOrphanedElements(IEnumerable<string> orphanedIds, ILogger logger)
{
var toDelete = new List<ElementId>();
Expand Down
60 changes: 28 additions & 32 deletions src/Libraries/RevitNodes/AnalysisDisplay/AbstractAnalysisDisplay.cs
Original file line number Diff line number Diff line change
@@ -1,11 +1,11 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Runtime.Serialization;
using Autodesk.DesignScript.Runtime;
using Autodesk.Revit.DB;
using Autodesk.Revit.DB.Analysis;
using DynamoUnits;
using Newtonsoft.Json;
using RevitServices.Elements;
using RevitServices.Persistence;
using RevitServices.Transactions;
Expand All @@ -17,57 +17,41 @@ namespace Revit.AnalysisDisplay
/// support serialization.
/// </summary>
[SupressImportIntoVM]
[Serializable]
public class SpmPrimitiveIdPair : ISerializable
public class SpmPrimitiveIdPair
{
public long SpatialFieldManagerID { get; set; }
public List<int> PrimitiveIds { get; set; }
public void GetObjectData(SerializationInfo info, StreamingContext context)

public SpmPrimitiveIdPair(long spatialFieldManagerID, List<int> primitiveIds)
{
info.AddValue("SpatialFieldManagerID", SpatialFieldManagerID, typeof(long));
info.AddValue("PrimitiveIds", PrimitiveIds, typeof(List<int>));
SpatialFieldManagerID = spatialFieldManagerID;
PrimitiveIds = primitiveIds;
}

public SpmPrimitiveIdPair()
{
SpatialFieldManagerID = long.MinValue;
PrimitiveIds = new List<int>();
}

public SpmPrimitiveIdPair(SerializationInfo info, StreamingContext context)
{
SpatialFieldManagerID = (long) info.GetValue("SpatialFieldManagerID", typeof (long));
PrimitiveIds =
(List<int>)
info.GetValue("PrimitiveIds", typeof(List<int>));
}
}

[SupressImportIntoVM]
[Serializable]
public class SpmRefPrimitiveIdListPair : ISerializable
public class SpmRefPrimitiveIdListPair
{
public long SpatialFieldManagerID { get; set; }
public Dictionary<Reference, int> RefIdPairs { get; set; }
public void GetObjectData(SerializationInfo info, StreamingContext context)

public SpmRefPrimitiveIdListPair(long spatialFieldManagerID, Dictionary<Reference, int> refIdPairs)
{
info.AddValue("SpatialFieldManagerID", SpatialFieldManagerID, typeof(long));
info.AddValue("ReferencePrimitiveIds", RefIdPairs, typeof(Dictionary<Reference, int>));
SpatialFieldManagerID = spatialFieldManagerID;
RefIdPairs = refIdPairs;
}

public SpmRefPrimitiveIdListPair()
{
SpatialFieldManagerID = long.MinValue;
RefIdPairs = new Dictionary<Reference, int>();
}

public SpmRefPrimitiveIdListPair(SerializationInfo info, StreamingContext context)
{
SpatialFieldManagerID = (long)info.GetValue("SpatialFieldManagerID", typeof(long));
RefIdPairs =
(Dictionary<Reference, int>)
info.GetValue("ReferencePrimitiveIds", typeof(Dictionary<Reference, int>));
}
}

/// <summary>
Expand Down Expand Up @@ -240,11 +224,21 @@ void IDisposable.Dispose()
protected Tuple<SpatialFieldManager, List<int>> GetElementAndPrimitiveIdFromTrace()
{
// This is a provisional implementation until we can store both items in trace
var id = ElementBinder.GetRawDataFromTrace();
if (id == null)
var traceString = ElementBinder.GetRawDataFromTrace();

if (String.IsNullOrEmpty(traceString))
return null;

var idPair = id as SpmPrimitiveIdPair;
SpmPrimitiveIdPair idPair = null;
try
{
idPair = JsonConvert.DeserializeObject<SpmPrimitiveIdPair>(traceString);
}
catch
{
//do nothing
}

if (idPair == null)
return null;

Expand Down Expand Up @@ -277,7 +271,9 @@ protected void SetElementAndPrimitiveIdsForTrace(SpatialFieldManager manager, Li
SpatialFieldManagerID = manager.Id.Value,
PrimitiveIds = primitiveIds
};
ElementBinder.SetRawDataForTrace(idPair);

var serializedTraceData = JsonConvert.SerializeObject(idPair);
ElementBinder.SetRawDataForTrace(serializedTraceData);
Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

does it make more sense to have the ElementBinder internally do the serialization / deserialization?

}

/// <summary>
Expand Down
22 changes: 17 additions & 5 deletions src/Libraries/RevitNodes/AnalysisDisplay/FaceAnalysisDisplay.cs
Original file line number Diff line number Diff line change
@@ -1,7 +1,6 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Runtime.Serialization;
using Analysis;
using Dynamo.Graph.Nodes;
using Autodesk.DesignScript.Runtime;
Expand All @@ -14,6 +13,7 @@
using Surface = Autodesk.DesignScript.Geometry.Surface;
using UV = Autodesk.Revit.DB.UV;
using View = Revit.Elements.Views.View;
using Newtonsoft.Json;

namespace Revit.AnalysisDisplay
{
Expand Down Expand Up @@ -278,11 +278,21 @@ public static FaceAnalysisDisplay ByViewAndFaceAnalysisData(
protected Tuple<SpatialFieldManager, Dictionary<Reference, int>> GetElementAndRefPrimitiveIdFromTrace()
{
// This is a provisional implementation until we can store both items in trace
var id = ElementBinder.GetRawDataFromTrace();
if (id == null)
var traceString = ElementBinder.GetRawDataFromTrace();

if (String.IsNullOrEmpty(traceString))
return null;

var idPair = id as SpmRefPrimitiveIdListPair;
SpmRefPrimitiveIdListPair idPair = null;
try
{
idPair = JsonConvert.DeserializeObject<SpmRefPrimitiveIdListPair>(traceString);
}
catch
{
//do nothing
}

if (idPair == null)
return null;

Expand Down Expand Up @@ -315,7 +325,9 @@ protected void SetElementAndRefPrimitiveIdsForTrace(SpatialFieldManager manager,
SpatialFieldManagerID = manager.Id.Value,
RefIdPairs = keyValues
};
ElementBinder.SetRawDataForTrace(idPair);

var serializedTraceData = JsonConvert.SerializeObject(idPair);
ElementBinder.SetRawDataForTrace(serializedTraceData);
}

protected void SetElementAndRefPrimitiveIdsForTrace()
Expand Down
Loading