The problem
public void levelRemap()
{
Document doc = this.ActiveUIDocument.Document;
UIDocument uidoc = this.ActiveUIDocument;
Level level = doc.GetElement(uidoc.Selection.PickObject(ObjectType.Element, "Select level")) as Level;
Level levelBelow = new FilteredElementCollector(doc)
.OfClass(typeof(Level))
.Cast<Level>()
.OrderBy(q => q.Elevation)
.Where(q => q.Elevation <= level.Elevation)
.FirstOrDefault();
if (levelBelow == null)
{
TaskDialog.Show("Error", "No level below " + level.Elevation);
return;
}
List<string> paramsToAdjust = new List<string> { "Base Offset", "Sill Height", "Top Offset"};
List<Element> elements = new FilteredElementCollector(doc).WherePasses(new ElementLevelFilter(level.Id)).ToList();
using (Transaction t = new Transaction(doc, "Level Remap"))
{
t.Start();
foreach (Element e in elements)
{
foreach (Parameter p in e.Parameters)
{
if (p.StorageType != StorageType.ElementId || p.IsReadOnly)
continue;
if (p.AsElementId() != level.Id)
continue;
double elevationDiff = level.Elevation - levelBelow.Elevation;
p.Set(levelBelow.Id);
foreach (string paramName in paramsToAdjust)
{
Parameter pToAdjust = e.LookupParameter(paramName);
if (pToAdjust != null && !pToAdjust.IsReadOnly)
pToAdjust.Set(pToAdjust.AsDouble() + elevationDiff);
}
}
}
t.Commit();
}
}
Great Harry. I have develop something similar years ago for my company. Our app display a list
of elements attached to each level and a list of levels to choose one and change the elements. There are some special cases for certains categories that require more code to make it work I all.
Hi Harry, Just testing this out on the advanced sample project and a few errors pop up. In addition it seems that floors at the selected level are getting deleted
I added “Height Offset From Level” to the paramsToAdjust list. I’m starting to see how this works. There’d be an issue with elements associated to two levels ie top and bottom. Columns for axample have a bottom level and a top level. Walls can be attached to a top level. How would you adjust the script to account for this?
Hi Alexis – You are right that some additional work would be needed to take this proof-of-concept to the next level (pun intended!). For example, the Top Offset should only be set if the Top Level (for columns) or Top Constraint (for walls) is set.
Hi Harry!
I’m trying to apply de code into r2019.2 but have no luck; what goes prior the “public partial class ThisApplication” ?
I tried:
public partial class ThisDocument
{
}
But again, no luck :c
There is something i’m quoting that the classes can’t see, i don’t know what…
public partial class ThisDocument
{
public partial class ThisApplication
{
public void levelRemap()
{
Document doc = this.ActiveUIDocument.Document;
UIDocument uidoc = this.ActiveUIDocument;
Level level = doc.GetElement(uidoc.Selection.PickObject(ObjectType.Element, “Select level”)) as Level;
Level levelBelow = new FilteredElementCollector(doc)
.OfClass(typeof(Level))
.Cast()
.OrderBy(q => q.Elevation)
.Where(q => q.Elevation <= level.Elevation)
.FirstOrDefault();
if (levelBelow == null)
{
TaskDialog.Show("Error", "No level below " + level.Elevation);
return;
}
List paramsToAdjust = new List { “Base Offset”, “Sill Height”, “Top Offset”};
List elements = new FilteredElementCollector(doc).WherePasses(new ElementLevelFilter(level.Id)).ToList();
using (Transaction t = new Transaction(doc, “Level Remap”))
{
t.Start();
foreach (Element e in elements)
{
foreach (Parameter p in e.Parameters)
{
if (p.StorageType != StorageType.ElementId || p.IsReadOnly)
continue;
if (p.AsElementId() != level.Id)
continue;
double elevationDiff = level.Elevation – levelBelow.Elevation;
p.Set(levelBelow.Id);
foreach (string paramName in paramsToAdjust)
{
Parameter pToAdjust = e.LookupParameter(paramName);
if (pToAdjust != null && !pToAdjust.IsReadOnly)
pToAdjust.Set(pToAdjust.AsDouble() + elevationDiff);
}
}
}
t.Commit();
}
}
}
}
}
Hi
I’m not sure exactly what the problem is that you are having, but these posts might help.
When i run the script it remaps to the lowest level in the project. how can i modify the script so it moves to the next lowest level in the sequence for instance instead of from level 4 to 1 it goes from level 4 to 3? thank you
Hi – This is the code that finds the level below. Right now it sorts the levels by elevation, finds only the level’s with an elevation less than the selected level, and then takes the first level in the resulting list. If you’d like to learn more about how this works, you might start with
https://www.c-sharpcorner.com/article/linq-for-beginners/ and search the internet for more information about
c# linq orderby
c# linq where
Level levelBelow = new FilteredElementCollector(doc)
.OfClass(typeof(Level))
.Cast()
.OrderBy(q => q.Elevation)
.Where(q => q.Elevation <= level.Elevation)
.FirstOrDefault();
Thank you! I chose to do .OrderByDescending. And under .Where I changed “<= level.Elevation" to " < level.Elevation" that achieved the results i was looking for
Level levelBelow = new FilteredElementCollector(doc)
.OfClass(typeof(Level))
.Cast()
.OrderByDescending(q => q.Elevation)
.Where(q => q.Elevation < level.Elevation)
.FirstOrDefault();