Skip to content

Commit

Permalink
Merge remote-tracking branch 'origin/dev' into deserialization2
Browse files Browse the repository at this point in the history
  • Loading branch information
adamhathcock committed Oct 24, 2024
2 parents 5b88448 + 3088fae commit a830816
Show file tree
Hide file tree
Showing 7 changed files with 62 additions and 57 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -45,6 +45,11 @@ internal sealed class RevitSendBinding : RevitBaseBinding, ISendBinding
/// </summary>
private ConcurrentDictionary<string, byte> ChangedObjectIds { get; set; } = new();

/// <summary>
/// We need it to get UniqueId whenever it is not available i.e. GetDeletedElementIds returns ElementId and cannot find its Element to get UniqueId. We store them both just before send to remember later.
/// </summary>
private ConcurrentDictionary<string, string> IdMap { get; } = new();

public RevitSendBinding(
IRevitIdleManager idleManager,
RevitContext revitContext,
Expand Down Expand Up @@ -129,15 +134,22 @@ public async Task Send(string modelCardId)
var activeUIDoc =
RevitContext.UIApplication?.ActiveUIDocument
?? throw new SpeckleException("Unable to retrieve active UI document");
List<ElementId> revitObjects = modelCard

List<Element> elements = modelCard
.SendFilter.NotNull()
.GetObjectIds()
.Select(uid => activeUIDoc.Document.GetElement(uid))
.Where(el => el is not null) // NOTE: elements can get deleted from the host app.
.Select(el => el.Id)
.Where(el => el is not null)
.ToList();

if (revitObjects.Count == 0)
foreach (Element element in elements)
{
IdMap[element.Id.ToString()] = element.UniqueId;
}

List<ElementId> elementIds = elements.Select(el => el.Id).ToList();

if (elementIds.Count == 0)
{
// Handle as CARD ERROR in this function
throw new SpeckleSendFilterException("No objects were found to convert. Please update your publish filter!");
Expand All @@ -146,7 +158,7 @@ public async Task Send(string modelCardId)
var sendResult = await scope
.ServiceProvider.GetRequiredService<SendOperation<ElementId>>()
.Execute(
revitObjects,
elementIds,
modelCard.GetSendInfo(_speckleApplication.Slug),
_operationProgressManager.CreateOperationProgressEventHandler(Parent, modelCardId, cancellationToken),
cancellationToken
Expand Down Expand Up @@ -242,25 +254,25 @@ private bool HaveUnitsChanged(Document doc)
private async Task RunExpirationChecks()
{
var senders = Store.GetSenders();
string[] objectIdsList = ChangedObjectIds.Keys.ToArray();
// string[] objectIdsList = ChangedObjectIds.Keys.ToArray();
var doc = RevitContext.UIApplication?.ActiveUIDocument.Document;

if (doc == null)
{
return;
}

// Note: We're using unique ids as application ids in revit, so cache eviction must happen by those.
// NOTE: this is currently broken when deleting freestanding elements (e.g. unhosted elements)
// To reproduce, draw two unconnected walls, send, delete one wall -> no expiration notice
// I do not yet know the solution besides going back to element ids, but it would mean revisiting why we switched to unique ids (conflicting ids)
var objUniqueIds = objectIdsList
.Select(id => new ElementId(Convert.ToInt32(id)))
.Select(doc.GetElement)
.Where(el => el is not null)
.Select(el => el.UniqueId)
.ToList();
_sendConversionCache.EvictObjects(objUniqueIds);
var objUniqueIds = new List<string>();
foreach (string changedElementId in ChangedObjectIds.Keys.ToArray())
{
if (IdMap.TryGetValue(changedElementId, out var uniqueId))
{
objUniqueIds.Add(uniqueId);
}
}

var unpackedObjectIds = _elementUnpacker.GetUnpackedElementIds(objUniqueIds);
_sendConversionCache.EvictObjects(unpackedObjectIds);

// Note: we're doing object selection and card expiry management by old school ids
List<string> expiredSenderIds = new();
Expand All @@ -282,6 +294,9 @@ private async Task RunExpirationChecks()
// That's why don't bother for now how to get rid of from dup logic in other bindings.
private async Task OnDocumentChanged()
{
_sendConversionCache.ClearCache();
IdMap.Clear();

if (_cancellationManager.NumberOfOperations > 0)
{
_cancellationManager.CancelAllOperations();
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -54,6 +54,7 @@ IConverterSettingsStore<Civil3dConversionSettings> converterSettings

case CDB.FeatureLine:
case CDB.Parcel:
case CDB.ParcelSegment:
return new() { _curveConverter.Convert(entity.BaseCurve) };

// for any entities where basecurve prop doesn't make sense
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -31,7 +31,7 @@ IConverterSettingsStore<Civil3dConversionSettings> converterSettings
_converterSettings = converterSettings;
}

public List<Base> GetDisplayValue(CDB.Entity entity)
public List<Base>? GetDisplayValue(CDB.Entity entity)
{
switch (entity)
{
Expand All @@ -56,7 +56,7 @@ public List<Base> GetDisplayValue(CDB.Entity entity)
return new() { gridSurfaceMesh };

default:
return new();
return null;
}
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -59,9 +59,10 @@ public Base Convert(CDB.Entity target)
civilObject["baseCurves"] = baseCurves;
}

// extract display value
List<Base> display = _displayValueExtractor.GetDisplayValue(target);
if (display.Count > 0)
// extract display value.
// If object has no display but has basecurves, use basecurves for display instead (for viewer selection)
List<Base>? display = _displayValueExtractor.GetDisplayValue(target) ?? baseCurves?.Select(o => (Base)o).ToList();
if (display is not null)
{
civilObject["displayValue"] = display;
}
Expand Down Expand Up @@ -104,7 +105,6 @@ public Base Convert(CDB.Entity target)
private List<Base>? GetSiteChildren(CDB.Site site)
{
List<Base> parcels = new();

using (var tr = _settingsStore.Current.Document.Database.TransactionManager.StartTransaction())
{
foreach (ADB.ObjectId parcelId in site.GetParcelIds())
Expand All @@ -115,6 +115,7 @@ public Base Convert(CDB.Entity target)

tr.Commit();
}

return parcels.Count > 0 ? parcels : null;
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -252,11 +252,6 @@ private void ExtractPartProperties(CDB.Part part, Dictionary<string, object?> di
catchmentProperties["featureLineIds"] = GetSpeckleApplicationIdsFromCollection(site.GetFeatureLineIds());
}

if (site.GetParcelIds().Count > 0)
{
catchmentProperties["parcelIds"] = GetSpeckleApplicationIdsFromCollection(site.GetParcelIds());
}

return catchmentProperties;
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -292,7 +292,7 @@ CDB.FeatureLineCollection featurelineCollection in offsetFeaturelineCollection.F
};
speedsCount++;
}
designCriteriaDict["Design Speeds"] = designSpeedsDict;

if (designSpeedsDict.Count > 0)
{
designCriteriaDict["Design Speeds"] = designSpeedsDict;
Expand Down
Original file line number Diff line number Diff line change
@@ -1,6 +1,5 @@
using Speckle.Converters.Common;
using Speckle.Converters.Common.Objects;
using Speckle.Sdk;

namespace Speckle.Converters.Civil3dShared.ToSpeckle.Raw;

Expand All @@ -22,37 +21,30 @@ IConverterSettingsStore<Civil3dConversionSettings> settingsStore

public SOG.Arc Convert(CDB.AlignmentSubEntityArc target)
{
// alignment arcs do not have the same properties as autocad arcs.
// we're assuming they are always 2d arcs on the xy plane to calculate the midpoint
string units = _settingsStore.Current.SpeckleUnits;

// calculate midpoint of chord as between start and end point
AG.Point2d chordMid =
new((target.StartPoint.X + target.EndPoint.X) / 2, (target.StartPoint.Y + target.EndPoint.Y) / 2);

// calculate sagitta as radius minus distance between arc center and chord midpoint
double sagitta = target.Radius - target.CenterPoint.GetDistanceTo(chordMid);

// get unit vector from arc center to chord mid
AG.Vector2d midVector = target.CenterPoint.GetVectorTo(chordMid);
AG.Vector2d unitMidVector = midVector.DivideBy(midVector.Length);

// get midpoint of arc by moving chord mid point the length of the sagitta along mid vector
// if greater than 180 >, move in other direction of distance radius + radius - sagitta
// in the case of an exactly perfect half circle arc...🤷‍♀️
AG.Point2d midPoint = chordMid.Add(unitMidVector.MultiplyBy(sagitta));
try
// calculate the mid vector (center to PI point (intersection of tangents)
// note: what is the PI point for a perfect half circle?
AG.Point2d piPoint = target.PIPoint;
double midVectorX = piPoint.X - target.CenterPoint.X;
double midVectorY = piPoint.Y - target.CenterPoint.Y;
double midVectorMag = Math.Sqrt(Math.Pow(midVectorX, 2.0) + Math.Pow(midVectorY, 2));
double midScalingVectorX = target.Radius * midVectorX / midVectorMag;
double midScalingVectorY = target.Radius * midVectorY / midVectorMag;
if (target.Delta > Math.PI)
{
if (target.GreaterThan180) // this can throw : The property gets an invalid value according to the entity's constraint type.
{
midPoint = chordMid.Add(unitMidVector.Negate().MultiplyBy(2 * target.Radius - sagitta));
}
midScalingVectorX *= -1;
midScalingVectorY *= -1;
}
catch (Exception e) when (!e.IsFatal()) { } // continue with original midpoint if GreaterThan180 doesn't apply to this arc

double midPointX = target.CenterPoint.X + midScalingVectorX;
double midPointY = target.CenterPoint.Y + midScalingVectorY;

// find arc plane (normal is in clockwise dir)
var center3 = new AG.Point3d(target.CenterPoint.X, target.CenterPoint.Y, 0);
AG.Plane plane = target.Clockwise
? new AG.Plane(center3, AG.Vector3d.ZAxis.MultiplyBy(-1))
: new AG.Plane(center3, AG.Vector3d.ZAxis);
AG.Plane plane = new AG.Plane(center3, AG.Vector3d.ZAxis);

// create arc
SOG.Arc arc =
Expand All @@ -74,21 +66,22 @@ public SOG.Arc Convert(CDB.AlignmentSubEntityArc target)
},
midPoint = new()
{
x = midPoint.X,
y = midPoint.Y,
x = midPointX,
y = midPointY,
z = 0,
units = units
},
plane = _planeConverter.Convert(plane),
radius = target.Radius,
angleRadians = target.Delta,
length = target.Length,
units = units,

// additional alignment subentity props
["startStation"] = target.StartStation,
["endStation"] = target.EndStation,
["startDirection"] = target.StartDirection,
["endDirection"] = target.EndDirection,
["delta"] = target.Delta,
["deflectedAngle"] = target.DeflectedAngle,
["minumumRadius"] = target.MinimumRadius
};
Expand Down

0 comments on commit a830816

Please sign in to comment.