Replace material

Replace material

Anonymous
Not applicable
3,896 Views
37 Replies
Message 1 of 38

Replace material

Anonymous
Not applicable

Dear all,

is it possible to substitute in a selected element (mainly wall or floor) the type of material?

E.g. basic wall - material A into basic wall - material B. 

I'm wondering also if my basic wall has more than one material, is it still possible to substitute all of them with just a specific material?

Thanks in advance for your support

0 Likes
3,897 Views
37 Replies
Replies (37)
Message 2 of 38

aignatovich
Advisor
Advisor

Hi!

 

Revit API seldom provides any functionality you can't do manually. So you have 2 possible options to archive what you want. You can create a new wall type, adjust the compound structure and apply it to the wall. Or you can create parts and replace the material of specific layer parts elements if it is suitable for your purposes.

0 Likes
Message 3 of 38

Anonymous
Not applicable

thanks @aignatovich for your quick reply. I thought to replace all the material inside the wall type with the new material

 

0 Likes
Message 4 of 38

aignatovich
Advisor
Advisor

For the first option something like this:

var wallType = (WallType)wall.WallType.Duplicate(newName);

var compoundStructure = wallType.GetCompoundStructure();

var layerIdxs = Enumerable.Range(0, compoundStructure.LayerCount)
	.Where(x => compoundStructure.GetMaterialId(x) == sourceMaterialId)
	.ToList();

foreach(var layerIdx in layerIdxs) {
	compoundStructure.SetMaterialId(layerIdx, destMaterialId);
}

wall.ChangeTypeId(wallType.Id);

 

For the second option:

PartUtils.CreateParts(doc, new[] {wall.Id}) ;

doc.Regenerate();

var parts = PartUtils.GetAssociatedParts(doc, wall.Id, false, false)
	.Select(doc.GetElement)
	.Where(x => x.get_Parameter(BuiltInParameter.DPART_MATERIAL_ID_PARAM).AsElementId() == sourceMaterialId)
	.ToList();
	
foreach(var part in parts) {
	part.get_Parameter(BuiltInParameter.DPART_MATERIAL_BY_ORIGINAL).Set(0);
	
	doc.Regenerate();
	
	part.get_Parameter(BuiltInParameter.DPART_MATERIAL_ID_PARAM).Set(destMaterialId);
}
Message 5 of 38

Anonymous
Not applicable

@aignatovich thanks for your comments, I'm using the compoudStructure code from Revit SDK, but instead of a new material I would like to take one already exist in the material list 

0 Likes
Message 6 of 38

aignatovich
Advisor
Advisor

So, use FilteredElementCollector to find this existing material and pass its id to CompoundStructureLayer constructor or CompoundStructure.SetMaterialId method

Message 7 of 38

Anonymous
Not applicable

Could @aignatovich  or @Anonymous  paste the part of code post 6 please? I'm not so expert as you, thanks! 🤗

0 Likes
Message 8 of 38

Anonymous
Not applicable

Through CompoundStructure SDK example I was able to reach something, but I still have a small issue, how can I insert just one material rather than two? If I delete the substrateLayer I get error

 

 public void CreateCSforWall(Wall wall)
        {

            // Get CompoundStructure
            WallType wallType = wall.WallType;
           //wallType.Name = wallType.Name + "_WithNewCompoundStructure";
            CompoundStructure wallCS = wallType.GetCompoundStructure();
            // Get material for CompoundStructureLayer


            Material concrete = CreateSampleConcreteMaterial();

            // Create CompoundStructureLayers and add the materials created above to them.
            List<CompoundStructureLayer> csLayers = new List<CompoundStructureLayer>();
            CompoundStructureLayer substrateLayer = new CompoundStructureLayer(0.1, MaterialFunctionAssignment.Substrate, ElementId.InvalidElementId);
            CompoundStructureLayer structureLayer = new CompoundStructureLayer(0.5, MaterialFunctionAssignment.Structure, concrete.Id);

            csLayers.Add(substrateLayer);
            csLayers.Add(structureLayer);

            // // Set the created layers to CompoundStructureLayer
            wallCS.SetLayers(csLayers);


            //Set which layer is used for structural analysis
            wallCS.StructuralMaterialIndex = 1;


            // Set the new wall CompoundStructure to the type of wall.
            wallType.SetCompoundStructure(wallCS);
        }
Message 9 of 38

Anonymous
Not applicable

@jeremytammik  could you have a look to my last post please? I need your valuable help to overcome my small issue please

0 Likes
Message 10 of 38

jeremytammik
Autodesk
Autodesk

Many thanks to Alexander for his professional help.

 

@Anonymous , you don't really need any help at all; you are perfectly capable of researching and solving this yourself. 

 

Follow the guidelines on How to research to find a Revit API solution:

 

https://thebuildingcoder.typepad.com/blog/2017/01/virtues-of-reproduction-research-mep-settings-ontology.html#3

 

As Alexander points out, you need to research how to solve this manually in the user interface first.

 

There are several ways, and maybe they all violate the BIM in various ways.

 

Here a a more brutal approach to achieve what you are asking for:

 

https://thebuildingcoder.typepad.com/blog/2020/06/changing-element-colour-and-material.html

 

It answers your question, but will probably not do your BIM much good...

 

 

 



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

Message 11 of 38

lukaskohout
Advocate
Advocate

What error do you get?

Have you tried to set shell layers?

wallCS.StructuralMaterialIndex = 0;
wallCS.SetNumberOfShellLayers(ShellLayerType.Interior, 0);
wallCS.SetNumberOfShellLayers(ShellLayerType.Exterior, 0);

Hitting Accepted Answer is a Community Contribution from me as well as from you.
======================================================================
Message 12 of 38

Anonymous
Not applicable

thanks @jeremytammik for your effort, it's exactly what I need, but when I tried to change material it doesn't change any material, is it missing something?

 

@lukaskohout really thanks! It works perfectly!!! can I ask you another small favor please? I would like to keep the same thickness as the wall selected, how should I change the following syntax?

 // Get CompoundStructure
            WallType wallType = wall.WallType;
            //wallType.Name = wallType.Name + "_WithNewCompoundStructure";
            CompoundStructure wallCS = wallType.GetCompoundStructure();
            
            // Get material for CompoundStructureLayer
            Material concrete = CreateSampleConcreteMaterial();

            // Create CompoundStructureLayers and add the materials created above to them.
            List<CompoundStructureLayer> csLayers = new List<CompoundStructureLayer>();
            CompoundStructureLayer structureLayer = new CompoundStructureLayer(1.5, MaterialFunctionAssignment.Structure, concrete.Id);

            //csLayers.Add(substrateLayer);
            csLayers.Add(structureLayer);

            // // Set the created layers to CompoundStructureLayer
            wallCS.SetLayers(csLayers);


            //Set which layer is used for structural analysis
            wallCS.StructuralMaterialIndex = 0;
            wallCS.SetNumberOfShellLayers(ShellLayerType.Interior, 0);
            wallCS.SetNumberOfShellLayers(ShellLayerType.Exterior, 0);

           // Set the new wall CompoundStructure to the type of wall.
            wallType.SetCompoundStructure(wallCS);
        }

 

0 Likes
Message 13 of 38

lukaskohout
Advocate
Advocate
double currentWidth = wallCS.GetLayerWidth(0);

You just need to know the index of the layer.


Hitting Accepted Answer is a Community Contribution from me as well as from you.
======================================================================
Message 14 of 38

Anonymous
Not applicable

thanks @lukaskohout  for your support! For the first type of wall it works perfect, but if I tried to apply it in a second different type of wall I get the following error

Capture.JPG

0 Likes
Message 15 of 38

lukaskohout
Advocate
Advocate

Looks like you already have the material with the name in the project. Try creating a different one. with different name.

General rule is to check if something already exists in the project before creating it. 


Hitting Accepted Answer is a Community Contribution from me as well as from you.
======================================================================
Message 16 of 38

Anonymous
Not applicable

Yes you are right, that material already exist because I imported it the first time when I applied it to the first wall. So in this case if I want to use the same feature twice (but the second time applied to a different wall type) I should avoid the creation of the already existing material. Any tips?

0 Likes
Message 17 of 38

lukaskohout
Advocate
Advocate

In the SampleMaterialConcrete function check if the material you are creating does not already exist in the project. You can do that by name or ideally by Material.Id

 

Or if you want to make it easier for yourself, you can wrap the material creation line to try-catch block, that way the error when creating a material already present in project will not cause the code to stop.

https://docs.microsoft.com/en-gb/dotnet/csharp/language-reference/keywords/try-catch


Hitting Accepted Answer is a Community Contribution from me as well as from you.
======================================================================
Message 18 of 38

s.borello
Advisor
Advisor

You don't need API to do this... just create a different wall type and add whatever material you desire. 

0 Likes
Message 19 of 38

RPTHOMAS108
Mentor
Mentor

The reality is that if you are an AEC consultant then the wall types you use are based on the company specification for such you have developed over numerous projects. It would be unusual or inefficient not to have all the wall types you commonly use already defined in a Revit file for import (made up of the materials your specification covers).

 

On the other hand, say you’ve developed those types and due to project development (contractor/employer proposals) etc. the materials need to change (for acoustic/sustainability etc.). Do you manually remake the wall types with the new material, or do you create new types from existing types changing the one material that has changed? Probably you don't want to make new types due to the instance assignment of type based sweeps/reveals etc. So instead should swap the material in the existing types. In theory you could redefine the material itself, but it may be used in elements where the change isn’t required. I'm not surprised people would turn to the API for this kind of task. 

Message 20 of 38

lukaskohout
Advocate
Advocate

I would also add, from my experience that sometimes you want to create new wall types and materials and you need API to do that.

In my previous job, we developed a Revit addin that was connected to building material manufacturers product database and from the data in the database it created new wall, floor and ceiling types in project. New types had different compound structures, materials assigned and parameters filled. Doing that manually is really tideous, nevermind that you would have to find the data from product lists and put them into project yourself.

 

At that time you had to duplicate an existing type in project and then assing the new compound structure. But maybe that changed now,


Hitting Accepted Answer is a Community Contribution from me as well as from you.
======================================================================