Automatyczne łączenie ścian i stropów

W trakcie modelowania Revit automatycznie łączy ze sobą przenikające się ściany, znacznie przyspieszając proces rysowania. Nie dzieję się tak jednak dla ścian i stropów, co skutkuje dodatkową pracą np. przy tworzeniu przekroi. Może również powodować nieprawidłowe wartości przedmiarów. Takie działania mogą być jednak zautomatyzowane przy pomocy prostego skryptu API.

Na początek musimy odnaleźć wszystkie elementy modelu będące ścianami i (oddzielnie) stropami. Pomijamy obiekty będące definicją typów.

FilteredElementCollector walls = new FilteredElementCollector(doc)
				.OfCategory(BuiltInCategory.OST_Walls).WhereElementIsNotElementType();
FilteredElementCollector floors = new FilteredElementCollector(doc)
				.OfCategory(BuiltInCategory.OST_Floors).WhereElementIsNotElementType();

Następnie, upewniwszy się że działamy wewnątrz transakcji, sprawdzamy każdą parę ściana-strop pod kątem wzajemnego przenikania. Z uwagi na efektywność działania skryptu nie badamy dokładnej geometrii obiektów a jedynie ich prostopadłościenne obrysy (bounding box).

W celu uniknięcia błędów dla każdego elementu upewniamy się, że jego obrys jest prawidłowym obiektem (nie zwraca wartości null). Przenikanie się dwóch prostopadłościanów testujemy za pomocą krótkiej funkcji pomocniczej, której nie będę dokładniej opisywał – jest za to zawarta w końcowym kodzie.

foreach(Wall w in walls) {					
  BoundingBoxXYZ wBB = w.get_BoundingBox(null);						
  if(wBB!=null) foreach(Floor f in floors) {			
    BoundingBoxXYZ fBB = f.get_BoundingBox(null);														
    if(fBB!=null) if(bbIntersect(wBB,fBB)) {		
    }
  }
}

Gdy znajdziemy już parę ściana-strop, podejrzewaną o przenikanie się, sprawdzamy czy elementy te nie są już ze sobą połączone. Jeśli nie, łączymy je. Aby nie przerywać działania całego kodu w wypadku błędu jednej z par, funkcję łączenia umieszczamy w sekwencji try..catch.

if(!JoinGeometryUtils.AreElementsJoined(doc,w,f)) {
  try {							
    JoinGeometryUtils.JoinGeometry(doc, w, f);
  }	
  catch(Autodesk.Revit.Exceptions.ApplicationException)   
  {									
  }
}

Całość kodu, wraz z funkcjami pomocniczymi, może wyglądać następująco:

		private bool overlap1D(double a1, double a2, double b1, double b2) {
			
			if(a2>=b1 && b2>=a1) return true;
			
			return false;
			
		}
		
		private bool bbIntersect(BoundingBoxXYZ A, BoundingBoxXYZ B) {
						
			return overlap1D(A.Min.X,A.Max.X,B.Min.X,B.Max.X) &&
				overlap1D(A.Min.Y,A.Max.Y,B.Min.Y,B.Max.Y) &&
				overlap1D(A.Min.Z,A.Max.Z,B.Min.Z,B.Max.Z);
			
		}
		
		public void joinFloorWall() {
			
			Document doc = this.ActiveUIDocument.Document;
			UIDocument uiDoc = new UIDocument(doc);
						
			FilteredElementCollector walls = new FilteredElementCollector(doc)
				.OfCategory(BuiltInCategory.OST_Walls).WhereElementIsNotElementType();
			FilteredElementCollector floors = new FilteredElementCollector(doc)
				.OfCategory(BuiltInCategory.OST_Floors).WhereElementIsNotElementType();
			

			using(Transaction t = new Transaction(doc,"Join walls to floors")) {
				
				t.Start();				

				foreach(Wall w in walls) {	
				
				BoundingBoxXYZ wBB = w.get_BoundingBox(null);	
					
				if(wBB!=null) foreach(Floor f in floors) {					
								
						BoundingBoxXYZ fBB = f.get_BoundingBox(null);
									
						if(fBB!=null) if(bbIntersect(wBB,fBB)) {							
									
							if(!JoinGeometryUtils.AreElementsJoined(doc,w,f)) {
								try {							
									JoinGeometryUtils.JoinGeometry(doc, w, f);
								}
								catch(Autodesk.Revit.Exceptions.ApplicationException) 
								{									
								}
							}			   
								
						}
					}
			    }					
				
				t.Commit();				
				
			}			
			
		}
Posts created 32

Dodaj komentarz

Twój adres email nie zostanie opublikowany.

Related Posts

Begin typing your search term above and press enter to search. Press ESC to cancel.

Back To Top