Формирование отверстий под балки
Главная › Форумы › Задать вопрос › Формирование отверстий под балки
- В этой теме 0 ответов, 1 участник, последнее обновление 2 года, 5 месяцев назад сделано Максим.
-
АвторСообщения
-
МаксимУчастник
Доброго времени суток, я новичок в python и dynamo. Столкнулся с необходимостью автоматизировать создание отверстий для конструкции типа балка (каркас несущий). Нашел формирование отверстий для коммуникаций из ролика https://www.youtube.com/watch?v=wPbfz6YxNJw. Проблемы с которыми я столкнулся: оригинал работал с шириной и высотой коммуникаций через BuiltInParameter, но у балки эти параметры спрятаны в свойствах типа, по умолчанию там доступна длина. Я пытался добраться до параметров высоты и ширины балки и отправить в BuiltInParameter, но он принимает только Guid, а как я понял, возможно плохо понял, но у этих параметров нет Guid, я попытался создать их через ExternalDefinitionCreationOptions. не помогло. тогда решил работать от длины, и вычислять отверстия в зависимости от длины. В итоге вылезла ошибка, File “<string>”, line 218, in getCommunicationDirection UnboundLocalError: Local variable ‘direction’ referenced before assignment.
Помогите, пожалуйста, с адаптацией или подскажите как еще это можно сделать если через подобную адаптацию это сделать невозможно.
оригинал из ролика
<p>
#————————————————————————————————————————-
# ЗАГРУЗКА СИСТЕМНЫХ БИБЛИОТЕК И ОПЦИЙ
#————————————————————————————————————————-
import clr
import math
from System.Collections.Generic import *clr.AddReference(‘RevitAPI’)
import Autodesk
from Autodesk.Revit.DB import *# Определение опций Revit API
options = Options()
intersectionOptions = SolidCurveIntersectionOptions() # для нахождения пересечения
nonStructural = Autodesk.Revit.DB.Structure.StructuralType.NonStructural # для вставки семейства в основу# Категории коммуникаций
pipeCategory = BuiltInCategory.OST_PipeCurves
ductCategory = BuiltInCategory.OST_DuctCurves
conduitCategory = BuiltInCategory.OST_Conduit
cableTrayCategory = BuiltInCategory.OST_CableTray
frameCat = BuiltInCategory.OST_StructuralFramingclr.AddReference(‘RevitServices’)
import RevitServices
from RevitServices.Persistence import DocumentManager
from RevitServices.Transactions import TransactionManager#————————————————————————————————————————-
# ВХОДНЫЕ ДАННЫЕ
#————————————————————————————————————————-# Типоразмеры семейств проёмов
rectangularFamilyForWall = UnwrapElement(IN[0]) # прямоугольной для стен
roundFamilyForWall = UnwrapElement(IN[1]) # круглой для стен
rectangularFamilyForFloor = UnwrapElement(IN[2]) # прямоугольной для плит
roundFamilyForFloor = UnwrapElement(IN[3]) # круглой для плит# Экземпляры выбранных конструкций (если выбраны)
selectElements = UnwrapElement(IN[4])
try:
selectElements.Count
except:
if selectElements is not None:
selectElements = [UnwrapElement(IN[4])]# Запас сторон для проёмов
isReservByCoefficient = IN[5] # запас задаётся коэффициентом?
if isReservByCoefficient:
reserv = IN[6] # запас для проёма как отношение сторон
else:
reserv = IN[6] / 304.8 # запас для проёма в мм# Условия формирования круглого, а не прямоугольного, проёма
maxAspectRatio = IN[7] # максимальное отношение сторон коммуникации для круглого отверстия
maxDiameter = IN[8] / 304.8 # максимальный диаметр для круглого отверстия# Работа со связанными файлами
isLinkDocument = IN[9] # конструкции в связанном файле?
nameLinkDocument = IN[10] # часть имени связанного файла с конструкциями# Типы обрабатываемых конструкций
includeWalls = IN[11] # обрабатывть стены?
includeFloors = IN[12] # обрабатывать перекрытия?# Значения параметров проёмов
comment = IN[13] # дата или другой комментарий (для версионирования)
disciplineName = IN[14] # дисциплина проёма# Имена параметров проёмов
disciplineParameter = IN[15] # параметр дисциплины
diameterParameter = IN[16] # параметр диаметра
widthParameter = IN[17] # параметр ширины
heightParameter = IN[18] # параметр высоты
commentParameter = IN[19] # параметр комментария#————————————————————————————————————————-
# ПОЛУЧЕНИЕ ДАННЫХ ИЗ ПРОЕКТА
#————————————————————————————————————————-# Получение текущего проекта
currentDoc = DocumentManager.Instance.CurrentDBDocument# Получение списка связанных файлов
linkInstances = FilteredElementCollector(currentDoc).OfClass(RevitLinkInstance)# Определение файла, в котором содержатся конструкции
if isLinkDocument:
a = 0
for linkInstance in linkInstances:
if nameLinkDocument in linkInstance.Name:
docWithCommunications = linkInstance.GetLinkDocument()
a = 1
# Если связанный файл с подходящим именем не найден, то берём текущий файл
if a == 0:
docWithCommunications = currentDoc
else:
docWithCommunications = currentDoc#————————————————————————————————————————-
# СОЗДАНИЕ КЛАССОВ И ФУНКЦИЙ
#————————————————————————————————————————-# Класс стены с нужными свойствами
class WallObject:
# Инициализация свойств класса
def __init__(self, instance, width, A, B, solid, level):
self.instance = instance # экзмепляр стены в модели
self.width = width # толщина стены
self.A = A # коэффициент A уравнения прямой стены
self.B = B # коэффициент B уравнения прямой стены
self.solid = solid # объёмная геометрия стены
self.level = level # уровень, на котором размещена стена# Класс плиты с нужными свойствами
class FloorObject:
def __init__(self, instance, solid, level):
self.instance = instance # экземпляр плиты в модели
self.solid = solid # объёмная геометрия плиты
self.level = level # уровень, на котором размещена плита# Класс коммуникации с нужными свойствами
class CommunicationObject:
def __init__(self, width, height, A, B, C, direction, centerPoint):
self.width = width # ширина сечения коммуникации
self.height = height # высота сечения коммуникации
self.A = A # коэффициент A уравнения прямой коммуникации
self.B = B # коэффициент B уравнения прямой коммуникации
self.C = C # коэффициент C уравнения прямой коммуникации
self.direction = direction # направление для расположения проёма плиты
self.centerPoint = centerPoint # центр пересечения коммуникации и конструкции# Функция получения координат начальной и конечной точки линии
def getLineCoordinates(line):
endPoint0 = line.GetEndPoint(0) # получение начальной точки кривой
endPoint1 = line.GetEndPoint(1) # получение конечной точки кривой
x0 = endPoint0.X; y0 = endPoint0.Y; z0 = endPoint0.Z # получение координат начальной точки
x1 = endPoint1.X; y1 = endPoint1.Y; z1 = endPoint1.Z # получение координат начальной точки
coordinates = x0, y0, z0, x1, y1, z1
return coordinates# Функция получения объёмной геометрии конструкции
def getSolid(construction):
geometry = construction.get_Geometry(options)
for object in geometry:
solid = object
return solid# Функция создания экземпляра класса Wall
def createWallObject(wall):
width = wall.Width # получение толщины экземпляра стены
x0, y0, z0, x1, y1, z1 = getLineCoordinates(wall.Location.Curve) # получение координат прямой эскиза стены
A = y0 – y1 # получение коэффициента A уравнения прямой
B = x1 – x0 # получение коэффициента B уравнения прямой
solid = getSolid(wall) # получение объёмной геометрии стены
level = currentDoc.GetElement(wall.LevelId) # получение уровня, на котором размещена стена
wallObject = WallObject(wall, width, A, B, solid, level) # создание экземпляра класса WallObject
return wallObject# Функция создания экземпляра класса Floor
def createFloorObject(floor):
solid = getSolid(floor) # получение объёмной геометрии плиты
level = currentDoc.GetElement(floor.LevelId) # получение уровня, на котором размещена плиты
floorObject = FloorObject(floor, solid, level) # создание экземпляра класса FloorObject
return floorObject# Функция получения всех, либо только выбранных экземпляров класса в модели
def getInstances(revitClass):
selectIds = List[ElementId]()
if selectElements is not None:
for select in selectElements:
selectIds.Add(select.Id)
instances = FilteredElementCollector(currentDoc, selectIds).OfClass(revitClass).WhereElementIsNotElementType().ToElements()
else:
instances = FilteredElementCollector(currentDoc).OfClass(revitClass).WhereElementIsNotElementType().ToElements()
return instances# Функция создания проёмов в экземпляре конструкции для коммуникаций конкретного типа
def createOpenings(category, constructionObject):# Функция создания экземпляра класса Communication
def createCommunication(communication):# Функция получения размеров сечений коммуникации
def getCommunicationSize():
# Для труб
if category == pipeCategory:
diameter = communication.get_Parameter(BuiltInParameter.RBS_PIPE_OUTER_DIAMETER).AsDouble()
width = diameter
height = diameter
# Для воздухововдов
elif category == ductCategory:
try:
diameter = communication.get_Parameter(BuiltInParameter.RBS_CURVE_DIAMETER_PARAM).AsDouble()
width = diameter
height = diameter
except:
width = communication.get_Parameter(BuiltInParameter.RBS_CURVE_WIDTH_PARAM).AsDouble()
height = communication.get_Parameter(BuiltInParameter.RBS_CURVE_HEIGHT_PARAM).AsDouble()
# Для коробов
elif category == conduitCategory:
diameter = communication.get_Parameter(BuiltInParameter.RBS_CONDUIT_DIAMETER_PARAM).AsDouble()
width = diameter
height = diameter
# Для кабельных лотков
elif category == cableTrayCategory:
width = communication.get_Parameter(BuiltInParameter.RBS_CABLETRAY_WIDTH_PARAM).AsDouble()
height = communication.get_Parameter(BuiltInParameter.RBS_CABLETRAY_HEIGHT_PARAM).AsDouble()
return width, height
# Функция получения координат начальной и конечной точки линий коммуникации
def getCommunicationLineCoordinates():
curve = communication.Location.Curve # определение кривой эскиза коммуникации
lines = constructionObject.solid.IntersectWithCurve(curve, intersectionOptions) # определение линий пересечения коммуникации и конструкции
try:
line = lines.GetCurveSegment(0) # взятие первой и единственной линии
except:
line = curve # в некоторых случаях берём саму кривую
coordinates = getLineCoordinates(line)
return coordinates# Функция определения направления коммуникации
def getCommunicationDirection():# Функция определения нормали к грани воздуховода или лотка для проёмов в плитах
def getFaceNormal():
# Для определения направления берём боковую сторону воздуховода или лотка и находим нормаль к ней
geometry = communication.get_Geometry(options)
for object in geometry:
solid = object
faces = solid.Faces
for face in faces:
_faceNormal = face.FaceNormal
# Проверка того, что берётся именно боковая грань
if _faceNormal.Z == 0:
faceNormal = _faceNormal
return faceNormal# Для плит направление проёма определяется из геометрии коммуникации
if constructionObject.__class__.__name__ == ‘FloorObject’:
# Для воздуховодов (могут быть как круглые, так и прямоугольные)
if category == ductCategory:
try:
diameter = communication.get_Parameter(BuiltInParameter.RBS_CURVE_DIAMETER_PARAM).AsDouble()
direction = XYZ(0, 0, 0)
except:
# В случае прямоугольных или овальных воздухововдов берём нормаль к грани
direction = getFaceNormal()
# Для кабельных лотков (всегда прямоугольные)
elif category == cableTrayCategory:
# В отличие от воздуховода, у кабельного лотка берём не нормаль, а касательную
faceNormal = getFaceNormal()
direction = XYZ(faceNormal.Y, -faceNormal.X, faceNormal.Z)
# Для труб и коробов (всегда круглые)
else:
direction = XYZ(0, 0, 0)
return directionwidth, height = getCommunicationSize() # получение ширины и высоты сечения коммуникации
x0, y0, z0, x1, y1, z1 = getCommunicationLineCoordinates() # получение координат линии эскиза коммуникации
A = y0 – y1 # получение коэффициента A уравнения прямой
B = x1 – x0 # получение коэффициента B уравнения прямой
C = z1 – z0 # получение коэффициента C уравнения прямой
direction = getCommunicationDirection() # получения направления коммуникаций (для проёмов в плите)
centerPoint = XYZ((x0 + x1) / 2, (y0 + y1) / 2, (z0 + z1) / 2) # получение центра пересечения коммуникации и конструкции
# Cоздание экземпляра класса Communication
communicationObject = CommunicationObject(width, height, A, B, C, direction, centerPoint)
return communicationObject# Функция создания экземпляра проёма
def createOpening(rectangularFamily, roundFamily, minWidth, minHeight, centerPoint, direction):# Функция создания экземпляра проёма и назначения геометрических параметров
def _createOpening(maxSide, minSide, openingWidth, openingHeight):
# Если значения допустимы для создания круглого проёма, то создание и назначение диаметра
if maxSide / minSide <= maxAspectRatio and maxSide <= maxDiameter:
if constructionObject.__class__.__name__ == ‘WallObject’:
_opening = currentDoc.Create.NewFamilyInstance(centerPoint, roundFamily, constructionObject.instance, constructionObject.level, nonStructural)
else:
_opening = currentDoc.Create.NewFamilyInstance(centerPoint, roundFamily, direction, constructionObject.instance, nonStructural)
_opening.get_Parameter(BuiltInParameter.FAMILY_LEVEL_PARAM).Set(constructionObject.level.Id)
_opening.LookupParameter(diameterParameter).Set(maxSide)
# Если нет, то создание прямоугольного проёма и задание её ширины и высоты
else:
if constructionObject.__class__.__name__ == ‘WallObject’:
_opening = currentDoc.Create.NewFamilyInstance(centerPoint, rectangularFamily, constructionObject.instance, constructionObject.level, nonStructural)
else:
_opening = currentDoc.Create.NewFamilyInstance(centerPoint, rectangularFamily, direction, constructionObject.instance, nonStructural)
_opening.get_Parameter(BuiltInParameter.FAMILY_LEVEL_PARAM).Set(constructionObject.level.Id)
_opening.LookupParameter(widthParameter).Set(openingWidth)
_opening.LookupParameter(heightParameter).Set(openingHeight)
return _opening# Проверка того, возможно ли создать проём, и создание
if minWidth is not None and minHeight is not None:
# Определение ширины проёма с учётом допуска
if isReservByCoefficient: # если допуск задан коэффициентом
openingWidth = minWidth * reserv
openingHeight = minHeight * reserv
else: # если допуск задан в миллиметрах
openingWidth = minWidth + reserv
openingHeight = minHeight + reserv
# Округление сторон до сантиметров
openingWidth = round(openingWidth * 304.8, -1) / 304.8
openingHeight = round(openingHeight * 304.8, -1) / 304.8
# Создание проёма
if openingHeight > openingWidth:
opening = _createOpening(openingHeight, openingWidth, openingWidth, openingHeight) # случай, если высота больше ширины
else:
opening = _createOpening(openingWidth, openingHeight, openingWidth, openingHeight) # случай, если ширина больше высоты
# Установка других параметров проёма
opening.LookupParameter(disciplineParameter).Set(disciplineName)
opening.LookupParameter(commentParameter).Set(comment)
return opening
# Если проём нельзя создать
else:
message = ‘Коммуникация внутри конструкции’
return message# Функция создания проёма в стене
def createWallOpening(communicationObject):# Функция вычисления минимальной стороны проёма в стене
def getMinSide(cosin, communicationSide):
angle = round(math.degrees(math.acos(cosin))) # вычисление угла между коммуникацией и консутркцией из косинуса
if angle > 90:
angle = 180 – angle # определение острого угла при пересечении
angleRad = math.radians(angle) # перевод острого угла в радианы
if angle != 180 and angle != 0:
# Определение минимальной стороны проёма, если коммуникация не проходит вдоль конструкции
minSide = constructionObject.width / math.tan(angleRad) + communicationSide / math.sin(angleRad)
return minSide# Получение косинуса угла пересечения коммуникации и конструкции в плане для определения минимальной ширины проёма
try:
cosin = (constructionObject.A * communicationObject.A + constructionObject.B * communicationObject.B) / ((constructionObject.A**2 + constructionObject.B**2)**0.5 * (communicationObject.A**2 + communicationObject.B**2)**0.5)
except:
cosin = 1
minWidth = getMinSide(cosin, communicationObject.width)
# Получение угла пересечения коммуникации и конструкции по вертикали (то есть между трубой и горизонтальной плоскостью) для определения минимальной высоты проёма
cosin = communicationObject.C / ((communicationObject.A**2 + communicationObject.B**2 + communicationObject.C**2)**0.5)
minHeight = getMinSide(cosin, communicationObject.height) # определение минимальной высота проёма
rectangularFamily = rectangularFamilyForWall # семейство прямоугольного проёма в стене
roundFamily = roundFamilyForWall # семейство круглого проёма в стене
# Создание проёма
wallOpening = createOpening(rectangularFamily, roundFamily, minWidth, minHeight, communicationObject.centerPoint, None)
return wallOpening# Функция создания проёма в плите
def createFloorOpening(communicationObject):
minWidth = communicationObject.width # минимальная ширина проёма равна ширине коммуникации
minHeight = communicationObject.height # минимальная высота проёма равна высоте коммуникации
direction = communicationObject.direction # для проёмов в плите направление определяется из направления коммуникации
rectangularFamily = rectangularFamilyForFloor # семейство прямоугольного проёма в плите
roundFamily = roundFamilyForFloor # семейство круглого проёма в плите
# Создание проёма
floorOpening = createOpening(rectangularFamily, roundFamily, minWidth, minHeight, communicationObject.centerPoint, direction)
return floorOpening# Получение всех, либо только выбранных экземпляров коммуникаций в модели (для каждого экземпляра конструкции берём заново)
communications = FilteredElementCollector(docWithCommunications).OfCategory(category).WhereElementIsNotElementType()
# Извлечение только тех экземпляров коммуникаций, которые пересекаются с геометрией конструкции
intersectingCommunications = communications.WherePasses(ElementIntersectsSolidFilter(constructionObject.solid)).ToElements()
# Формирование списка для созданных проёмов
openings = []
# Обработка полученных экземпляров коммуникаций
for communication in intersectingCommunications:
# Создание экземляра класса Communication
communicationObject = createCommunication(communication)
# Если конструкция является стеной
if constructionObject.__class__.__name__ == ‘WallObject’:
opening = createWallOpening(communicationObject)
# Если конструкция является плитой
else:
opening = createFloorOpening(communicationObject)
openings.append([communication, opening])
return openings#————————————————————————————————————————-
# ОБРАБОТКА МОДЕЛИ
#————————————————————————————————————————-# Получение всех экзмепляров стен и плит
walls = getInstances(Wall)
floors = getInstances(Floor)# Открытие транзакции
TransactionManager.Instance.EnsureInTransaction(currentDoc)# Обработка стен, если включена
if includeWalls:
# Активация загруженных семейств проёмов (если ещё не были использованы)
rectangularFamilyForWall.Activate()
roundFamilyForWall.Activate()
# Формирование выходного списка и создание проёмов для каждой стены с коммуникациями каждой категории
wallOpenings = []
for wall in walls:
wallObject = createWallObject(wall)
for category in [pipeCategory, ductCategory, conduitCategory, cableTrayCategory]:
openings = createOpenings(category, wallObject)
if openings.Count > 0:
wallOpenings.append(openings)
else:
wallOpenings = ‘Обработка стен отключена’# Обработка плит, если включена (аналогично)
if includeFloors:
rectangularFamilyForFloor.Activate()
roundFamilyForFloor.Activate()
floorOpenings = []
for floor in floors:
floorObject = createFloorObject(floor)
for category in [pipeCategory, ductCategory, conduitCategory, cableTrayCategory]:
openings = createOpenings(category, floorObject)
if openings.Count > 0:
wallOpenings.append(openings)
else:
floorOpenings = ‘Обработка плит отключена’# Закрытие транзакции
TransactionManager.Instance.TransactionTaskDone()#————————————————————————————————————————-
# ВЫХОДНЫЕ ДАННЫЕ
#————————————————————————————————————————-OUT = wallOpenings, floorOpenings
</p>
моя попытка его адаптировать
<p>
<div>
<div>import clr</div>
<div>import math</div>
<div>from System.Collections.Generic import *</div>
<div>clr.AddReference(‘RevitAPI’)</div>
<div>import Autodesk</div>
<div>from Autodesk.Revit.DB import *</div>
<div># Определение опций Revit API</div>
<div>options = Options()</div>
<div>intersectionOptions = SolidCurveIntersectionOptions() # для нахождения пересечения</div>
<div>nonStructural = Autodesk.Revit.DB.Structure.StructuralType.NonStructural # для вставки семейства в основу</div>
<div># Категории балки</div>
<div>frameCat = BuiltInCategory.OST_StructuralFraming</div>
<div>clr.AddReference(‘RevitServices’)</div>
<div>import RevitServices</div>
<div>from RevitServices.Persistence import DocumentManager</div>
<div>from RevitServices.Transactions import TransactionManager</div>
<div>#————————————————————————————————————————-</div>
<div># ВХОДНЫЕ ДАННЫЕ</div>
<div>#————————————————————————————————————————-</div>
<div># Типоразмеры семейств проёмов</div>
<div>rectangularFamilyForWall = UnwrapElement(IN[0]) # прямоугольной для стен</div>
<div>rectangularFamilyForFloor = UnwrapElement(IN[2]) # прямоугольной для плит</div>
<div># Экземпляры выбранных конструкций (если выбраны)</div>
<div>selectElements = UnwrapElement(IN[4])</div>
<div>try:</div>
<div> selectElements.Count</div>
<div>except:</div>
<div> if selectElements is not None:</div>
<div> selectElements = [UnwrapElement(IN[4])]</div>
<div># Запас сторон для проёмов</div>
<div>isReservByCoefficient = IN[5] # запас задаётся коэффициентом?</div>
<div>if isReservByCoefficient:</div>
<div> reserv = IN[6] # запас для проёма как отношение сторон</div>
<div>else:</div>
<div> reserv = IN[6] / 304.8 # запас для проёма в мм</div>
<div># Условия формирования круглого, а не прямоугольного, проёма</div>
<div># Работа со связанными файлами</div>
<div>isLinkDocument = IN[9] # конструкции в связанном файле?</div>
<div>nameLinkDocument = IN[10] # часть имени связанного файла с конструкциями</div>
<div># Типы обрабатываемых конструкций</div>
<div>includeWalls = IN[11] # обрабатывть стены?</div>
<div>includeFloors = IN[12] # обрабатывать перекрытия?</div>
<div># Значения параметров проёмов</div>
<div>comment = IN[13] # дата или другой комментарий (для версионирования)</div>
<div>disciplineName = IN[14] # дисциплина проёма</div>
<div># Имена параметров проёмов</div>
<div>disciplineParameter = IN[15] # параметр дисциплины</div>
<div>diameterParameter = IN[16] # параметр диаметра</div>
<div>widthParameter = IN[17] # параметр ширины</div>
<div>heightParameter = IN[18] # параметр высоты</div>
<div>commentParameter = IN[19] # параметр комментария</div>
<div>#————————————————————————————————————————-</div>
<div># ПОЛУЧЕНИЕ ДАННЫХ ИЗ ПРОЕКТА</div>
<div>#————————————————————————————————————————-</div>
<div># Получение текущего проекта</div>
<div>currentDoc = DocumentManager.Instance.CurrentDBDocument</div>
<div># Получение списка связанных файлов</div>
<div>linkInstances = FilteredElementCollector(currentDoc).OfClass(RevitLinkInstance)</div>
<div># Определение файла, в котором содержатся конструкции</div>
<div>if isLinkDocument:</div>
<div> a = 0</div>
<div> for linkInstance in linkInstances:</div>
<div> if nameLinkDocument in linkInstance.Name:</div>
<div> docWithCommunications = linkInstance.GetLinkDocument()</div>
<div> a = 1</div>
<div> # Если связанный файл с подходящим именем не найден, то берём текущий файл</div>
<div> if a == 0:</div>
<div> docWithCommunications = currentDoc</div>
<div>else:</div>
<div> docWithCommunications = currentDoc</div>
<div>#————————————————————————————————————————-</div>
<div># СОЗДАНИЕ КЛАССОВ И ФУНКЦИЙ</div>
<div>#————————————————————————————————————————-</div>
<div># Класс стены с нужными свойствами</div>
<div>class WallObject:</div>
<div> # Инициализация свойств класса</div>
<div> def __init__(self, instance, width, A, B, solid, level):</div>
<div> self.instance = instance # экзмепляр стены в модели</div>
<div> self.width = width # толщина стены</div>
<div> self.A = A # коэффициент A уравнения прямой стены</div>
<div> self.B = B # коэффициент B уравнения прямой стены</div>
<div> self.solid = solid # объёмная геометрия стены</div>
<div> self.level = level # уровень, на котором размещена стена</div>
<div># Класс плиты с нужными свойствами</div>
<div>class FloorObject:</div>
<div> def __init__(self, instance, solid, level):</div>
<div> self.instance = instance # экземпляр плиты в модели</div>
<div> self.solid = solid # объёмная геометрия плиты</div>
<div> self.level = level # уровень, на котором размещена плита</div>
<div># Класс балки с нужными свойствами</div>
<div>class BalkaObject:</div>
<div> def __init__(self, length, A, B, C, direction, centerPoint):</div>
<div> self.length = length # длина балки</div>
<div> self.A = A # коэффициент A уравнения прямой</div>
<div> self.B = B # коэффициент B уравнения прямой</div>
<div> self.C = C # коэффициент C уравнения прямой</div>
<div> self.direction = direction # направление для расположения проёма плиты</div>
<div> self.centerPoint = centerPoint # центр пересечения и конструкции</div>
<div># Функция получения координат начальной и конечной точки линии</div>
<div>def getLineCoordinates(line):</div>
<div> endPoint0 = line.GetEndPoint(0) # получение начальной точки кривой</div>
<div> endPoint1 = line.GetEndPoint(1) # получение конечной точки кривой</div>
<div> x0 = endPoint0.X; y0 = endPoint0.Y; z0 = endPoint0.Z # получение координат начальной точки</div>
<div> x1 = endPoint1.X; y1 = endPoint1.Y; z1 = endPoint1.Z # получение координат начальной точки</div>
<div> coordinates = x0, y0, z0, x1, y1, z1</div>
<div> return coordinates</div>
<div># Функция получения объёмной геометрии конструкции</div>
<div>def getSolid(construction):</div>
<div> geometry = construction.get_Geometry(options)</div>
<div> for object in geometry:</div>
<div> solid = object</div>
<div> return solid</div>
<div># Функция создания экземпляра класса Wall</div>
<div>def createWallObject(wall):</div>
<div> width = wall.Width # получение толщины экземпляра стены</div>
<div> x0, y0, z0, x1, y1, z1 = getLineCoordinates(wall.Location.Curve) # получение координат прямой эскиза стены</div>
<div> A = y0 – y1 # получение коэффициента A уравнения прямой</div>
<div> B = x1 – x0 # получение коэффициента B уравнения прямой</div>
<div> solid = getSolid(wall) # получение объёмной геометрии стены</div>
<div> level = currentDoc.GetElement(wall.LevelId) # получение уровня, на котором размещена стена</div>
<div> wallObject = WallObject(wall, width, A, B, solid, level) # создание экземпляра класса WallObject</div>
<div> return wallObject</div>
<div># Функция создания экземпляра класса Floor</div>
<div>def createFloorObject(floor):</div>
<div> solid = getSolid(floor) # получение объёмной геометрии плиты</div>
<div> level = currentDoc.GetElement(floor.LevelId) # получение уровня, на котором размещена плиты</div>
<div> floorObject = FloorObject(floor, solid, level) # создание экземпляра класса FloorObject</div>
<div> return floorObject</div>
<div># Функция получения всех, либо только выбранных экземпляров класса в модели</div>
<div>def getInstances(revitClass):</div>
<div> selectIds = List[ElementId]()</div>
<div> if selectElements is not None:</div>
<div> for select in selectElements:</div>
<div> selectIds.Add(select.Id)</div>
<div> instances = FilteredElementCollector(currentDoc, selectIds).OfClass(revitClass).WhereElementIsNotElementType().ToElements()</div>
<div> else:</div>
<div> instances = FilteredElementCollector(currentDoc).OfClass(revitClass).WhereElementIsNotElementType().ToElements()</div>
<div> return instances</div>
<div># Функция создания проёмов в экземпляре конструкции для коммуникаций конкретного типа</div>
<div>def createOpenings(category, constructionObject):</div>
<div> # Функция создания экземпляра класса Communication</div>
<div> def createCommunication(communication):</div>
<div></div>
<div> # Функция получения размеров сечений</div>
<div> def getCommunicationSize():</div>
<div> # Для балки</div>
<div> if category == frameCat:</div>
<div> length = communication.get_Parameter(BuiltInParameter.STRUCTURAL_FRAME_CUT_LENGTH).AsDouble()</div>
<div></div>
<div> return length</div>
<div></div>
<div># Функция получения координат начальной и конечной точки линий</div>
<div> def getCommunicationLineCoordinates():</div>
<div> curve = communication.Location.Curve # определение кривой эскиза</div>
<div> lines = constructionObject.solid.IntersectWithCurve(curve, intersectionOptions) # определение линий пересечения и конструкции</div>
<div> try:</div>
<div> line = lines.GetCurveSegment(0) # взятие первой и единственной линии</div>
<div> except:</div>
<div> line = curve # в некоторых случаях берём саму кривую</div>
<div> coordinates = getLineCoordinates(line)</div>
<div> return coordinates</div>
<div> # Функция определения направления</div>
<div> def getCommunicationDirection():</div>
<div></div>
<div> # Функция определения нормали к грани воздуховода или лотка для проёмов в плитах</div>
<div> def getFaceNormal():</div>
<div> # Для определения направления берём боковую сторону воздуховода или лотка и находим нормаль к ней</div>
<div> geometry = communication.get_Geometry(options)</div>
<div> for object in geometry:</div>
<div> solid = object</div>
<div> faces = solid.Faces</div>
<div> for face in faces:</div>
<div> _faceNormal = face.FaceNormal</div>
<div> # Проверка того, что берётся именно боковая грань</div>
<div> if _faceNormal.Z == 0:</div>
<div> faceNormal = _faceNormal</div>
<div> return faceNormal</div>
<div> # Для плит направление проёма определяется из геометрии</div>
<div> if constructionObject.__class__.__name__ == ‘FloorObject’:</div>
<div> # Для балки (только прямоугольные)</div>
<div> if category == frameCat:</div>
<div> try:</div>
<div> direction = XYZ(0, 0, 0)</div>
<div> except:</div>
<div> # В случае прямоугольных или овальных воздухововдов берём нормаль к грани</div>
<div> direction = getFaceNormal()</div>
<div> return direction</div>
<div> length = getCommunicationSize() # получение длины сечения</div>
<div> x0 = IN[20][0].X # координата стартовой точки</div>
<div> y0 = IN[20][0].Y # координата стартовой точки</div>
<div> z0 = IN[20][0].Z # координата стартовой точки</div>
<div> x1 = IN[21][0].X # координата конечной точки</div>
<div> y1 = IN[21][0].Y # координата конечной точки</div>
<div> z1 = IN[21][0].Z # координата конечной точки # получение координат линии эскиза</div>
<div> A = y0 – y1 # получение коэффициента A уравнения прямой</div>
<div> B = x1 – x0 # получение коэффициента B уравнения прямой</div>
<div> C = z1 – z0 # получение коэффициента C уравнения прямой</div>
<div> direction = getCommunicationDirection() # получения направления коммуникаций (для проёмов в плите)</div>
<div> centerPoint = XYZ((x0 + x1) / 2, (y0 + y1) / 2, (z0 + z1) / 2) # получение центра пересечения и конструкции</div>
<div> # Cоздание экземпляра класса Communication</div>
<div> communicationObject = CommunicationObject(width, height, A, B, C, direction, centerPoint)</div>
<div> return communicationObject</div>
<div> # Функция создания экземпляра проёма</div>
<div> def createOpening(rectangularFamily, roundFamily, minWidth, minHeight, centerPoint, direction):</div>
<div></div>
<div> # Функция создания экземпляра проёма и назначения геометрических параметров</div>
<div> def _createOpening(maxSide, minSide, openingWidth, openingHeight):</div>
<div></div>
<div> #создание прямоугольного проёма и задание её ширины и высоты</div>
<div> if constructionObject.__class__.__name__ == ‘WallObject’:</div>
<div> _opening = currentDoc.Create.NewFamilyInstance(centerPoint, rectangularFamily, constructionObject.instance, constructionObject.level, nonStructural)</div>
<div> else:</div>
<div> _opening = currentDoc.Create.NewFamilyInstance(centerPoint, rectangularFamily, direction, constructionObject.instance, nonStructural)</div>
<div> _opening.get_Parameter(BuiltInParameter.FAMILY_LEVEL_PARAM).Set(constructionObject.level.Id)</div>
<div> _opening.LookupParameter(widthParameter).Set(openingWidth)</div>
<div> _opening.LookupParameter(heightParameter).Set(openingHeight)</div>
<div> return _opening</div>
<div> # Проверка того, возможно ли создать проём, и создание</div>
<div> if minWidth is not None and minHeight is not None:</div>
<div> # Определение ширины проёма с учётом допуска</div>
<div> if isReservByCoefficient: # если допуск задан коэффициентом</div>
<div> openingWidth = minWidth * reserv</div>
<div> openingHeight = minHeight * reserv</div>
<div> else: # если допуск задан в миллиметрах</div>
<div> openingWidth = minWidth + reserv</div>
<div> openingHeight = minHeight + reserv</div>
<div> # Округление сторон до сантиметров</div>
<div> openingWidth = round(openingWidth * 304.8, -1) / 304.8</div>
<div> openingHeight = round(openingHeight * 304.8, -1) / 304.8</div>
<div> # Создание проёма</div>
<div> if openingHeight > openingWidth:</div>
<div> opening = _createOpening(openingHeight, openingWidth, openingWidth, openingHeight) # случай, если высота больше ширины</div>
<div> else:</div>
<div> opening = _createOpening(openingWidth, openingHeight, openingWidth, openingHeight) # случай, если ширина больше высоты</div>
<div> # Установка других параметров проёма</div>
<div> opening.LookupParameter(disciplineParameter).Set(disciplineName)</div>
<div> opening.LookupParameter(commentParameter).Set(comment)</div>
<div> return opening</div>
<div> # Если проём нельзя создать</div>
<div> else:</div>
<div> message = ‘Балка внутри конструкции'</div>
<div> return message</div>
<div># Функция создания проёма в стене</div>
<div> def createWallOpening(communicationObject):</div>
<div></div>
<div> # Функция вычисления минимальной стороны проёма в стене</div>
<div> def getMinSide(cosin, communicationSide):</div>
<div> angle = round(math.degrees(math.acos(cosin))) # вычисление угла между коммуникацией и консутркцией из косинуса</div>
<div> if angle > 90:</div>
<div> angle = 180 – angle # определение острого угла при пересечении</div>
<div> angleRad = math.radians(angle) # перевод острого угла в радианы</div>
<div> if angle != 180 and angle != 0:</div>
<div> # Определение минимальной стороны проёма, если коммуникация не проходит вдоль конструкции</div>
<div> minSide = constructionObject.width / math.tan(angleRad) + communicationSide / math.sin(angleRad)</div>
<div> return minSide</div>
<div> # Получение косинуса угла пересечения и конструкции в плане для определения минимальной ширины проёма</div>
<div> try:</div>
<div> cosin = (constructionObject.A * communicationObject.A + constructionObject.B * communicationObject.B) / ((constructionObject.A**2 + constructionObject.B**2)**0.5 * (communicationObject.A**2 + communicationObject.B**2)**0.5)</div>
<div> except:</div>
<div> cosin = 1</div>
<div> minWidth = getMinSide(cosin, communicationObject.width)</div>
<div> # Получение угла пересечения и конструкции по вертикали (то есть между трубой и горизонтальной плоскостью) для определения минимальной высоты проёма</div>
<div> cosin = communicationObject.C / ((communicationObject.A**2 + communicationObject.B**2 + communicationObject.C**2)**0.5)</div>
<div> minHeight = getMinSide(cosin, communicationObject.height) # определение минимальной высота проёма</div>
<div> rectangularFamily = rectangularFamilyForWall # семейство прямоугольного проёма в стене</div>
<div></div>
<div> # Создание проёма</div>
<div> wallOpening = createOpening(rectangularFamily, roundFamily, minWidth, minHeight, communicationObject.centerPoint, None)</div>
<div> return wallOpening</div>
<div># Функция создания проёма в плите</div>
<div> def createFloorOpening(communicationObject):</div>
<div> minWidth = communicationObject.length / (communicationObject.length / 4) # минимальная ширина проёма равна ширине</div>
<div> minHeight = communicationObject.length / (communicationObject.length / 3) # минимальная высота проёма равна высоте</div>
<div> direction = communicationObject.direction # для проёмов в плите направление определяется из направления</div>
<div> rectangularFamily = rectangularFamilyForFloor # семейство прямоугольного проёма в плите</div>
<div></div>
<div> # Создание проёма</div>
<div> floorOpening = createOpening(rectangularFamily, roundFamily, minWidth, minHeight, communicationObject.centerPoint, direction)</div>
<div> return floorOpening</div>
<div># Получение всех, либо только выбранных экземпляров коммуникаций в модели (для каждого экземпляра конструкции берём заново)</div>
<div> communications = FilteredElementCollector(docWithCommunications).OfCategory(category).WhereElementIsNotElementType()</div>
<div> # Извлечение только тех экземпляров коммуникаций, которые пересекаются с геометрией конструкции</div>
<div> intersectingCommunications = communications.WherePasses(ElementIntersectsSolidFilter(constructionObject.solid)).ToElements()</div>
<div> # Формирование списка для созданных проёмов</div>
<div> openings = []</div>
<div> # Обработка полученных экземпляров коммуникаций</div>
<div> for communication in intersectingCommunications:</div>
<div> # Создание экземляра класса Communication</div>
<div> communicationObject = createCommunication(communication)</div>
<div> # Если конструкция является стеной</div>
<div> if constructionObject.__class__.__name__ == ‘WallObject’:</div>
<div> opening = createWallOpening(communicationObject)</div>
<div> # Если конструкция является плитой</div>
<div> else:</div>
<div> opening = createFloorOpening(communicationObject)</div>
<div> openings.append([communication, opening])</div>
<div> return openings</div>
<div>#————————————————————————————————————————-</div>
<div># ОБРАБОТКА МОДЕЛИ</div>
<div>#————————————————————————————————————————-</div>
<div># Получение всех экзмепляров стен и плит</div>
<div>walls = getInstances(Wall)</div>
<div>floors = getInstances(Floor)</div>
<div># Открытие транзакции</div>
<div>TransactionManager.Instance.EnsureInTransaction(currentDoc)</div>
<div># Обработка стен, если включена</div>
<div>if includeWalls:</div>
<div> # Активация загруженных семейств проёмов (если ещё не были использованы)</div>
<div> rectangularFamilyForWall.Activate()</div>
<div> # Формирование выходного списка и создание проёмов для каждой стены с коммуникациями каждой категории</div>
<div> wallOpenings = []</div>
<div> for wall in walls:</div>
<div> wallObject = createWallObject(wall)</div>
<div> for category in [frameCat]:</div>
<div> openings = createOpenings(category, wallObject)</div>
<div> if openings.Count > 0:</div>
<div> wallOpenings.append(openings)</div>
<div>else:</div>
<div> wallOpenings = ‘Обработка стен отключена'</div>
<div># Обработка плит, если включена (аналогично)</div>
<div>if includeFloors:</div>
<div> rectangularFamilyForFloor.Activate()</div>
<div></div>
<div> floorOpenings = []</div>
<div> for floor in floors:</div>
<div> floorObject = createFloorObject(floor)</div>
<div> for category in [frameCat]:</div>
<div> openings = createOpenings(category, floorObject)</div>
<div> if openings.Count > 0:</div>
<div> wallOpenings.append(openings)</div>
<div>else:</div>
<div> floorOpenings = ‘Обработка плит отключена'</div>
<div># Закрытие транзакции</div>
<div>TransactionManager.Instance.TransactionTaskDone()</div>
<div># Назначьте вывод переменной OUT.</div>
<div>OUT = wallOpenings, floorOpenings</div>
</div>
</p> -
АвторСообщения
- Для ответа в этой теме необходимо авторизоваться.