using System;
using System.Collections.Generic;
using Autodesk.Revit.DB;
using Autodesk.Revit.DB.ExtensibleStorage;
using Autodesk.Revit.UI;
namespace Revit.SDK.Samples.DynamicModelUpdate.CS
{
///
/// Updater to automatically move a section in conjunction with the location of a window
///
public class SectionUpdater : IUpdater
{
internal SectionUpdater(AddInId addinID)
{
m_updaterId = new UpdaterId(addinID, new Guid("FBF3F6B2-4C06-42d4-97C1-D1B4EB593EFF"));
m_schemaId = new Guid("4DE4BE80-0857-4785-A7DF-8A8918851CB2");
}
// Registers itself with Revit
internal void Register(Document doc)
{
// create a window filter for the updater's scope
// we are only interested in two elements, one window and one section
// (for the sake of simplicity, we hard-coded the elements' unique Ids)
String windowUniqueId = "7f04899c-797b-4ad1-a9da-c6de1243ff83-00025ff6";
String sectionUniqueId = "4ca42fe1-e3e2-4bee-ab19-7d6e95cdf1bc-000261e8";
Element window = doc.get_Element(windowUniqueId);
if (window == null)
throw new Exception("Window was not found in the document.");
Element section = doc.get_Element(sectionUniqueId);
if (section == null)
throw new Exception("Section was not found in the document.");
// Setup collection of ids for the updater
List idsToWatch = new List();
m_windowId = window.Id;
idsToWatch.Add(m_windowId);
m_sectionId = section.Id;
UpdateInitialParameters(doc);
// Register and set a trigger for the section updater when the window changes
UpdaterRegistry.RegisterUpdater(this, doc);
UpdaterRegistry.AddTrigger(m_updaterId, doc, idsToWatch, Element.GetChangeTypeGeometry());
}
#region IUpdater members
// The Execute method for the updater
public void Execute(UpdaterData data)
{
try
{
Document doc = data.GetDocument();
FamilyInstance window = doc.get_Element(m_windowId) as FamilyInstance;
Element section = doc.get_Element(m_sectionId);
// iterate through modified elements to find the one we want the section to follow
foreach (ElementId id in data.GetModifiedElementIds())
{
if (id == m_windowId)
{
//Let's take this out temporarily.
bool enableLookup = false;
if (enableLookup)
m_schema = Schema.Lookup(m_schemaId); // (new Guid("{4DE4BE80-0857-4785-A7DF-8A8918851CB2}"));
Entity storedEntity = null;
storedEntity = window.GetEntity(m_schema);
//
// first we look-up X-Y-Z parameters, which we know are set on our windows
// and the values are set to the current coordinates of the window instance
Field fieldPosition = m_schema.GetField("Position");
XYZ oldPosition = storedEntity.Get(fieldPosition, DisplayUnitType.DUT_FEET_FRACTIONAL_INCHES);
TaskDialog.Show("Old position", oldPosition.ToString());
LocationPoint lp = window.Location as LocationPoint;
XYZ newPosition = lp.Point;
// XYZ has operator overloads
XYZ translationVec = newPosition - oldPosition;
// move the section by the same vector
if (!translationVec.IsZeroLength())
{
ElementTransformUtils.MoveElement(doc, section.Id, translationVec);
}
TaskDialog.Show("Moving", "Moving");
// Lookup the normal vector (i,j,we assume k=0)
Field fieldOrientation = m_schema.GetField("Orientation");
// Establish the old and new orientation vectors
XYZ oldNormal = storedEntity.Get(fieldOrientation, DisplayUnitType.DUT_FEET_FRACTIONAL_INCHES);
XYZ newNormal = window.FacingOrientation;
// If different, rotate the section by the angle around the location point of the window
double angle = oldNormal.AngleTo(newNormal);
// Need to adjust the rotation angle based on the direction of rotation (not covered by AngleTo)
XYZ cross = oldNormal.CrossProduct(newNormal).Normalize();
double sign = 1.0;
if (!cross.IsAlmostEqualTo(XYZ.BasisZ))
{
sign = -1.0;
}
angle *= sign;
if (Math.Abs(angle) > 0)
{
Line axis = doc.Application.Create.NewLineBound(newPosition, newPosition + XYZ.BasisZ);
ElementTransformUtils.RotateElement(doc, section.Id, axis, angle);
}
// update the parameters on the window instance (to be the current position and orientation)
storedEntity.Set(fieldPosition, newPosition, DisplayUnitType.DUT_FEET_FRACTIONAL_INCHES);
storedEntity.Set(fieldOrientation, newNormal, DisplayUnitType.DUT_FEET_FRACTIONAL_INCHES);
window.SetEntity(storedEntity);
}
}
}
catch (System.Exception ex)
{
TaskDialog.Show("Exception", ex.ToString());
}
return;
}
public UpdaterId GetUpdaterId()
{
return m_updaterId;
}
public string GetUpdaterName()
{
return "Associative Section Updater";
}
public string GetAdditionalInformation()
{
return "Automatically moves a section to maintain its position relative to a window";
}
public ChangePriority GetChangePriority()
{
return ChangePriority.Views;
}
#endregion
// Setup routine: updates parameters of the window to the appropriate values on load
internal void UpdateInitialParameters(Document doc)
{
Transaction t = new Transaction(doc, "Update parameters");
t.Start();
SchemaBuilder builder = new SchemaBuilder(m_schemaId); //(new Guid("{4DE4BE80-0857-4785-A7DF-8A8918851CB2}"));
builder.AddSimpleField("Position", typeof(XYZ)).SetUnitType(UnitType.UT_Length);
builder.AddSimpleField("Orientation", typeof(XYZ)).SetUnitType(UnitType.UT_Length);
builder.SetSchemaName("WallPositionData");
builder.SetDocumentation("Two points in a Window element that assist in placing a section view.");
builder.SetVendorId("adsk");
builder.SetApplicationGUID(doc.Application.ActiveAddInId.GetGUID());
m_schema = builder.Finish();
t.Commit();
t.Start();
Field fieldPosition = m_schema.GetField("Position");
Field fieldOrientation = m_schema.GetField("Orientation");
FamilyInstance window = doc.get_Element(m_windowId) as FamilyInstance;
Entity storageEntity = new Entity(m_schema);
LocationPoint lp = window.Location as LocationPoint;
XYZ location = lp.Point;
storageEntity.Set(fieldPosition, location, DisplayUnitType.DUT_FEET_FRACTIONAL_INCHES);
XYZ orientation = window.FacingOrientation;
storageEntity.Set(fieldOrientation, orientation, DisplayUnitType.DUT_FEET_FRACTIONAL_INCHES);
window.SetEntity(storageEntity);
t.Commit();
}
// private data:
private Guid m_schemaId;
private UpdaterId m_updaterId = null;
private ElementId m_windowId = null;
private ElementId m_sectionId = null;
private Schema m_schema;
}
}