/// <summary> /// Initialize a DirectShape element /// </summary> private void InitDirectShape(DesignScriptEntity shapeReference, string shapeName, Category category, Material material) { //Phase 1 - Check to see if a DirectShape exists in trace and should be rebound var oldShape = ElementBinder.GetElementAndTraceData <Autodesk.Revit.DB.DirectShape, DirectShapeState>(Document); //There was a oldDirectShape, rebind to that if (oldShape != null) { //set the directshape element this.InternalSetDirectShape(oldShape.Item1); //if the cateogryID has changed, we cannot continue to rebind and instead //will make a new directShape if (category.Id == this.InternalElement.Category.Id.IntegerValue) { //set the shape geometry of the directshape, this method passes in the actual input geo //and checks the directShapeState object at the elementId key in the input geo tags dictionary. //this check is used to determine if the geometry should be updated, this is done by checking //the sync guid in the DirectShapeState (a guid that is generated when geometry changes on //the revit element. //we also check the material, if it's different than the currently assigned material //then we need to rebuild the geo so that a new material is applied // this.InternalSetShape(shapeReference, new ElementId(material.Id), oldShape.Item2.syncId); this.InternalSetName(shapeReference, shapeName, material, category); return; } } //Phase 2- There was no existing shape, create one TransactionManager.Instance.EnsureInTransaction(Document); Autodesk.Revit.DB.DirectShape ds; //generate the geometry correctly depending on the type of geo var tessellatedShape = GenerateTessellatedGeo(shapeReference, new ElementId(material.Id)); //actually construct the directshape revit element ds = NewDirectShape(tessellatedShape, Document, new ElementId(category.Id), DirectShape.DYNAMO_DIRECTSHAPE_APP_GUID.ToString(), shapeName); InternalSetDirectShape(ds); InternalSetName(shapeReference, shapeName, material, category); //generate a new syncId for trace var traceData = new DirectShapeState(this, Guid.NewGuid().ToString(), new ElementId(material.Id)); //add the elementID:tracedata to the tags dictionary on the real protogeometry input shapeReference.Tags.AddTag(this.InternalElementId.ToString(), traceData); TransactionManager.Instance.TransactionTaskDone(); ElementBinder.SetRawDataForTrace(traceData); }
/// <summary> /// Sets the internalDirectShape's shape to point to some geometry, /// this method also generates tessellated geometry from the protogeometry object /// and sets the material of the generated Revit faces /// </summary> private void InternalSetShape(DesignScriptEntity shapeReference, ElementId materialId, string currentSyncId) { //if the elementID for the current directShape revitElement exists on the input Geometry AND //the value stored at that key is equal to the materialId we're trying to set AND //the previousState's syncId (in the tags dictionary) equals the current syncId (from trace) //then we do not need to regenerate //first lookup the state on the input geometry var previousState = shapeReference.Tags.LookupTag(this.InternalElementId.ToString()) as DirectShapeState; //then compare values if (previousState != null && previousState.materialId == materialId.IntegerValue && previousState.syncId == currentSyncId) { return; } TransactionManager.Instance.EnsureInTransaction(Document); var tessellatedShape = GenerateTessellatedGeo(shapeReference, materialId); this.InternalDirectShape.SetShape(tessellatedShape); //update the value in trace, since we had to modify the geometry we need a new syncId var updatedTraceData = new DirectShapeState(this, Guid.NewGuid().ToString(), materialId); ElementBinder.SetRawDataForTrace(updatedTraceData); //place new values in the tags dict if (shapeReference.Tags.LookupTag(this.InternalElementId.ToString()) == null) { shapeReference.Tags.AddTag(this.InternalElementId.ToString(), updatedTraceData); } else { var storedState = shapeReference.Tags.LookupTag(this.InternalElementId.ToString()) as DirectShapeState; storedState.syncId = updatedTraceData.syncId; storedState.materialId = updatedTraceData.materialId; storedState.IntID = updatedTraceData.IntID; storedState.StringID = updatedTraceData.StringID; } TransactionManager.Instance.TransactionTaskDone(); }