Формирование отверстий под балки

Главная Форумы Задать вопрос Формирование отверстий под балки

Помечено: ,

Просмотр 1 сообщения - с 1 по 1 (всего 1)
  • Автор
    Сообщения
  • #10821 Score: 0
    Максим
    Участник

    Доброго времени суток, я новичок в 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_StructuralFraming

    clr.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 direction

    width, 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>

Просмотр 1 сообщения - с 1 по 1 (всего 1)
  • Для ответа в этой теме необходимо авторизоваться.