Create view with coloured elements

Create view with coloured elements

Anonymous
Not applicable
2,219 Views
6 Replies
Message 1 of 7

Create view with coloured elements

Anonymous
Not applicable

Hello everyone,

 

I'm trying to create a view where all elements are colored depending on some parameters.

 

I've successfully created a view with the view style = shaded. Then I've tried to set a certain colour to the elements, but I'm only able to do that IF I read the materials in each element and then set the colour for each material in that element. 

 

Fig 1Fig 1Fig 2Fig 2

If I right-click the element and select 'Override Graphics in View>By Element', the windows on top will appear. As, by default, the surface patterns are set 'by material', this means that I have to change the colours of each material in the element. What I would like to do is to set the pattern to 'solid fill', so that I don't need to change the colour of each material.

 

I don't know if I'm being clear enough.

 

Thanks!

 

0 Likes
2,220 Views
6 Replies
Replies (6)
Message 2 of 7

jeremytammik
Autodesk
Autodesk

Before you do anything programmatically, you should always study the SDK samples.

 

Even before that, you should research the optimal approach manually through the user interface.

 

In this case, I believe that a view filter will achieve almost exactly what you are trying to do with a minimum of effort and maximum efficiency.

 

If that is indeed the case, the ElementFilter/ViewFilters sample will be of especial interest to you.

 

Cheers,

 

Jeremy

 



Jeremy Tammik
Developer Technical Services
Autodesk Developer Network, ADN Open
The Building Coder

Message 3 of 7

RPTHOMAS108
Mentor
Mentor

As Jeremy suggests visibility filters are a good suggestion but if you have a lot of variation i.e. beam sizes then you don't want lots of rules to achieve this. Such would be added to the UI and would then be hard for the user to find their ones within the generated ones.

 

What you are asking is possible and would work with either 'consistent colors' or 'shaded'. Disadvantage of overriding per view is you'd have to update it when new elements are created in the view via DMU etc. I have a routine that colours by beam sizes it's clear to the user that you run it at one point in time and if you need the view updated you run it again (that workflow is simple enough). For checking sizes or depths of beams is a good visual indicator.

Message 4 of 7

Anonymous
Not applicable

Thank you very much Jeremy and RPTHOMAS108,

 

I've found a solution that suits me based on your input. I'll paste it here in case someone else wants to reuse it:

 

IEnumerable<ViewFamilyType> viewFamilyTypes = from elem in new FilteredElementCollector(doc).OfClass(typeof(ViewFamilyType))
let type = elem as ViewFamilyType
where type.ViewFamily == ViewFamily.ThreeDimensional
select type;

//And then open transaction
using (Transaction trans = new Transaction(doc, "name"))
{
trans.Start();

//create view View3D new3D = View3D.CreateIsometric(doc, viewFamilyTypes.First().Id); new3D.Name = "Name"; //Set Visual Style to Shaded = 4 new3D.get_Parameter(BuiltInParameter.MODEL_GRAPHICS_STYLE).Set(4); OverrideGraphicSettings graphics = new OverrideGraphicSettings(); //set the transparency graphics.SetSurfaceTransparency(60); //define the level of detail graphics.SetDetailLevel(ViewDetailLevel.Coarse); int index = 0; //=========================== Verifications =========================== foreach (Element element in totalElements) { //max and minimum of indicator double max = LISTA.Max(); double min = LISTA.Min(); double indicator = LISTA[index]; //in here I do the verification and withdraw the value from a list //set the color Autodesk.Revit.DB.Color color = new Autodesk.Revit.DB.Color(0, 0, 0); if (indicator > 4 / 5 * (max - min)) { color = new Autodesk.Revit.DB.Color(255, 69, 0); // Orange Red } else if (indicator > 3 / 5 * (max - min)) { color = new Autodesk.Revit.DB.Color(255, 165, 0); // Orange } else if (indicator > 2 / 5 * (max - min)) { color = new Autodesk.Revit.DB.Color(255, 255, 224); // Light yellow } else if (indicator > 1 / 5 * (max - min)) { color = new Autodesk.Revit.DB.Color(173, 255, 47); // Green yellow } else { color = new Autodesk.Revit.DB.Color(0, 128, 0); // green } //set the color graphics.SetProjectionFillColor(color); //and then fill the Patern as 'Solid Fill' //a) find the solid fill Id List<FillPatternElement> fillPatternList = new FilteredElementCollector(doc).WherePasses(new ElementClassFilter(typeof(FillPatternElement))). ToElements().Cast<FillPatternElement>().ToList(); ElementId solidFillPatternId = null; foreach (FillPatternElement fp in fillPatternList) { if (fp.GetFillPattern().IsSolidFill) { solidFillPatternId = fp.Id; break; } } //b) set the id graphics.SetProjectionFillPatternId(solidFillPatternId); //and finally I override the graphic settings of the element new3D.SetElementOverrides(element.Id, graphics); index = 0; }
trans.Commit();
}
MessageBox.Show("Views created.");

 

it is highly likely this code can be simplified, but it worked for me for now.

 

Cheers

Ruben

 

0 Likes
Message 5 of 7

jeremytammik
Autodesk
Autodesk

Dear Ruben,

 

Thank you for the interesting sample code.

 

I do not see where the individual element is queried so that you can decide the appropriate colour for it.

 

On one hand, you iterate over the elements using `foreach (Element element in totalElements)`.

 

On the other, you determine the `indicator = LISTA[index]` and say, 'in here I do the verification and withdraw the value from a list'. 

 

Where does index come from?

 

Is there some code missing in between?

 

For instance, maybe the `index` could be read from a parameter value on the element?

 

Thank you for clarifying!

 

Cheers,

 

Jeremy

 

 

 



Jeremy Tammik
Developer Technical Services
Autodesk Developer Network, ADN Open
The Building Coder

0 Likes
Message 6 of 7

Anonymous
Not applicable

Dear Jeremy,

 

Basically I created a list of total elements in the project using one of your codes (thank you!):

 public List<Element> GetElementsProject(Document document)
        {
            Dictionary<string, Category> categories = new Dictionary<string, Category>();
            FilteredElementCollector collector = new FilteredElementCollector(document);//elementCollector will filter all elements in the project (i.e. doc)
            collector.WhereElementIsNotElementType().WhereElementIsViewIndependent().ToElements();
            List<Element> elements = new List<Element>();
            foreach (Element element in collector)
            {
                //make sure that, if the element is null, then I will not consider it (otherwise it would give errors later on)
                ElementType elementtype = document.GetElement(element.GetTypeId()) as ElementType;
                if (elementtype is null)
                    continue;
                if (null != element.Category
                  && 0 < element.Parameters.Size
                  && (element.Category.HasMaterialQuantities))
                {
                    if (!categories.ContainsKey(
                      element.Category.Name))
                    {
                        categories.Add(
                          element.Category.Name,
                          element.Category);
                    }
                    elements.Add(element);
                }
            }
            return elements;
        }

I think I just added a line where I make sure that, if an element type is null, I will ignore it (otherwise it would crash my code).

 

Then I query each element in that list (using the foreach block). Before the foreach block I create an instance int index =0; which, in the end of the foreach loop, I will add a value to it. Basically I could replace the 'foreach' with a 'for' block (still learning programming!). The index allow me to screen each variable inside the lists (e.g. ListA[index];), it isn't related with the parameter value.

 

What I have is List_A, which contain the name of all elements, and then List_B, which contains a Parameter_Value also for all elements. So they have the same size

E.g. index = 0; I will obtain the first instance in List_A (e.g. Wall1) and corresponding parameter in List_B (e.g. PV = 2), then index=1; I will obtain the second instance in List_A (e.g. Door1) and corresponding parameter in List_B (e.g. PV=5), and so on.

 

So, before the colouring, I've checked the max and min value in List_B. Then, the 'foreach' block will compare the Parameter_Value in each element with the max and min values.

 

I hope I've clarified the code a bit more now. If not, just let me know!

 

Cheers

Ruben

 

 

 

 

0 Likes
Message 7 of 7

Anonymous
Not applicable

By the way, when I migrated the code to Revit 2019 I noticed some functions were/will be obsolete. These are:

//these are obsolete
graphics.SetProjectionFillColor(color);
graphics.SetProjectionFillPatternId(solidFillPatternId);
//you can replace by these ones
graphics.SetSurfaceForegroundPatternColor(color);
graphics.SetSurfaceForegroundPatternId(solidFillPatternId);

0 Likes