{ "Uuid": "25ed7198-1fd7-42da-b9d4-43f37d599c2f", "IsCustomNode": false, "Description": "", "Name": "02_place_views_on_sheets", "ElementResolver": { "ResolutionMap": {} }, "Inputs": [], "Outputs": [], "Nodes": [ { "ConcreteType": "PythonNodeModels.PythonNode, PythonNodeModels", "Code": "# -*- coding: utf-8 -*-\r\n# 02 — Colocar vistas en hojas (viewport en punto del layout).\r\n#\r\n# IN[0] : tabla con cabeceras: SheetNumber, ViewName, OriginX_mm, OriginY_mm\r\n# y opcional OriginRef (ver abajo).\r\n# Modo BottomLeft (por defecto): esquina inf. izq. del layout; X/Y mm = esquina inf. izq. del\r\n# recuadro del viewport. Se crea primero en el centro del cajetín (o del outline de la hoja)\r\n# y luego Regenerate + MoveElement alinea esa esquina (más estable que Create en 0,0).\r\n# Modo TitleBlockCenter / SheetOutlineCenter: el CENTRO del viewport = centro calculado + X/Y mm.\r\n# IN[1] : (opcional) factor mm → unidades internas (pies). Por defecto 1/304.8 (mm a pies Revit).\r\n#\r\n# Salida: lista de Viewport creados y/o mensajes de error.\r\n# CPython3 / IronPython; tabla desde ImportExcel (File From Path + sheetName).\r\n\r\nimport sys\r\n\r\nimport clr\r\nclr.AddReference('RevitAPI')\r\nclr.AddReference('RevitServices')\r\nfrom Autodesk.Revit.DB import (\r\n BuiltInCategory,\r\n ElementTransformUtils,\r\n FilteredElementCollector,\r\n ViewSheet,\r\n View,\r\n Viewport,\r\n XYZ,\r\n)\r\nfrom RevitServices.Persistence import DocumentManager\r\nfrom RevitServices.Transactions import TransactionManager\r\n\r\n_PY3 = sys.version_info[0] >= 3\r\nMM_TO_FT_DEFAULT = 1.0 / 304.8\r\n\r\n\r\ndef _xyz_sub(a, b):\r\n return XYZ(a.X - b.X, a.Y - b.Y, a.Z - b.Z)\r\n\r\n\r\ndef _ustr(value):\r\n if value is None:\r\n return ''\r\n if _PY3:\r\n return str(value).strip()\r\n try:\r\n if isinstance(value, unicode):\r\n return value.strip()\r\n except NameError:\r\n pass\r\n return str(value).strip()\r\n\r\n\r\ndef _sheet_outline_center(sheet):\r\n bb = sheet.Outline\r\n if bb is None:\r\n return XYZ(0, 0, 0)\r\n if hasattr(bb, 'IsSet') and not bb.IsSet:\r\n return XYZ(0, 0, 0)\r\n u = (bb.Min.U + bb.Max.U) * 0.5\r\n v = (bb.Min.V + bb.Max.V) * 0.5\r\n return XYZ(u, v, 0)\r\n\r\n\r\ndef _title_block_center(doc, sheet):\r\n col = (\r\n FilteredElementCollector(doc, sheet.Id)\r\n .OfCategory(BuiltInCategory.OST_TitleBlocks)\r\n .WhereElementIsNotElementType()\r\n )\r\n xs0, ys0, xs1, ys1 = [], [], [], []\r\n for tb in col:\r\n box = tb.get_BoundingBox(sheet)\r\n if box is None:\r\n continue\r\n xs0.append(box.Min.X)\r\n ys0.append(box.Min.Y)\r\n xs1.append(box.Max.X)\r\n ys1.append(box.Max.Y)\r\n if not xs0:\r\n return None\r\n return XYZ(\r\n (min(xs0) + max(xs1)) * 0.5,\r\n (min(ys0) + max(ys1)) * 0.5,\r\n 0,\r\n )\r\n\r\n\r\ndef _create_anchor(doc, sheet):\r\n c = _title_block_center(doc, sheet)\r\n if c is not None:\r\n return c\r\n return _sheet_outline_center(sheet)\r\n\r\n\r\ndef _normalize_origin_ref(raw):\r\n if raw is None or _ustr(raw) == '':\r\n return 'BottomLeft'\r\n s = _ustr(raw).lower().replace(' ', '').replace('_', '')\r\n if s in ('titleblockcenter', 'tbcenter', 'cajetin'):\r\n return 'TitleBlockCenter'\r\n if s in ('sheetoutlinecenter', 'sheetcenter', 'outlinecenter', 'hoja'):\r\n return 'SheetOutlineCenter'\r\n if s in ('bottomleft', 'bl', 'esquinainferiorizquierda'):\r\n return 'BottomLeft'\r\n return 'BottomLeft'\r\n\r\n\r\ndef _exc_str(ex):\r\n if _PY3:\r\n return str(ex)\r\n try:\r\n return unicode(ex)\r\n except NameError:\r\n return str(ex)\r\n\r\n\r\ndef _to_py_list(obj, max_index=256):\r\n if obj is None:\r\n return []\r\n if isinstance(obj, (list, tuple)):\r\n return list(obj)\r\n try:\r\n return list(obj)\r\n except TypeError:\r\n pass\r\n out = []\r\n for i in range(max_index):\r\n try:\r\n out.append(obj[i])\r\n except Exception:\r\n break\r\n return out\r\n\r\n\r\ndef _normalize_table(data):\r\n rows = _to_py_list(data)\r\n return [_to_py_list(r) for r in rows]\r\n\r\n\r\ndef _dynamo_in_ports():\r\n raw = globals().get('IN', [])\r\n ports = _to_py_list(raw, max_index=32)\r\n if len(ports) == 0 and raw is not None:\r\n tmp = []\r\n for i in range(32):\r\n try:\r\n tmp.append(raw[i])\r\n except Exception:\r\n break\r\n ports = tmp\r\n return ports\r\n\r\n\r\ndef _headers(row):\r\n h = {}\r\n for i, x in enumerate(row):\r\n if x is None or x == '':\r\n continue\r\n name = _ustr(x)\r\n if len(name) > 0 and ord(name[0]) == 0xFEFF:\r\n name = name[1:].lstrip()\r\n if name:\r\n h[name] = i\r\n return h\r\n\r\n\r\ndef _get(row, headers, key):\r\n if key not in headers:\r\n return None\r\n i = headers[key]\r\n if i >= len(row):\r\n return None\r\n v = row[i]\r\n if v is None or v == '':\r\n return None\r\n return v\r\n\r\n\r\ndoc = DocumentManager.Instance.CurrentDBDocument\r\n_ports = _dynamo_in_ports()\r\nmm_to_ft = MM_TO_FT_DEFAULT\r\nif len(_ports) > 1 and _ports[1] is not None:\r\n try:\r\n mm_to_ft = float(_ports[1])\r\n except Exception:\r\n mm_to_ft = MM_TO_FT_DEFAULT\r\n\r\nrows = _normalize_table(_ports[0]) if len(_ports) > 0 else []\r\n\r\nif not rows or len(rows) < 2:\r\n OUT = ['Error: tabla vacía o sin datos.']\r\nelse:\r\n hdr = _headers(rows[0])\r\n need = ('SheetNumber', 'ViewName', 'OriginX_mm', 'OriginY_mm')\r\n missing = [k for k in need if k not in hdr]\r\n if missing:\r\n OUT = ['Error: faltan columnas: ' + ', '.join(missing)]\r\n else:\r\n data = rows[1:]\r\n sheets = {}\r\n for vs in FilteredElementCollector(doc).OfClass(ViewSheet).ToElements():\r\n sheets[_ustr(vs.SheetNumber)] = vs\r\n views = {}\r\n for v in FilteredElementCollector(doc).OfClass(View).ToElements():\r\n if v.IsTemplate:\r\n continue\r\n views[_ustr(v.Name)] = v\r\n\r\n created = []\r\n errors = []\r\n TransactionManager.Instance.EnsureInTransaction(doc)\r\n try:\r\n for r in data:\r\n sn = _get(r, hdr, 'SheetNumber')\r\n vn = _get(r, hdr, 'ViewName')\r\n if sn is None or vn is None:\r\n errors.append('Fila sin SheetNumber o ViewName')\r\n continue\r\n sn = _ustr(sn)\r\n vn = _ustr(vn)\r\n if not sn or not vn:\r\n errors.append('Fila sin SheetNumber o ViewName')\r\n continue\r\n if sn not in sheets:\r\n errors.append('Hoja no encontrada: ' + sn)\r\n continue\r\n if vn not in views:\r\n errors.append('Vista no encontrada: ' + vn)\r\n continue\r\n try:\r\n ox = float(_get(r, hdr, 'OriginX_mm') or 0) * mm_to_ft\r\n oy = float(_get(r, hdr, 'OriginY_mm') or 0) * mm_to_ft\r\n except Exception:\r\n errors.append('Origen inválido en fila hoja ' + sn)\r\n continue\r\n sheet = sheets[sn]\r\n view = views[vn]\r\n ref = _normalize_origin_ref(_get(r, hdr, 'OriginRef'))\r\n try:\r\n if ref == 'TitleBlockCenter':\r\n ac = _title_block_center(doc, sheet) or _sheet_outline_center(sheet)\r\n pt = XYZ(ac.X + ox, ac.Y + oy, 0)\r\n vp = Viewport.Create(doc, sheet.Id, view.Id, pt)\r\n elif ref == 'SheetOutlineCenter':\r\n ac = _sheet_outline_center(sheet)\r\n pt = XYZ(ac.X + ox, ac.Y + oy, 0)\r\n vp = Viewport.Create(doc, sheet.Id, view.Id, pt)\r\n else:\r\n pt0 = _create_anchor(doc, sheet)\r\n vp = Viewport.Create(doc, sheet.Id, view.Id, pt0)\r\n doc.Regenerate()\r\n outline = vp.GetBoxOutline()\r\n cur_min = outline.MinimumPoint\r\n target = XYZ(ox, oy, cur_min.Z)\r\n delta = _xyz_sub(target, cur_min)\r\n if abs(delta.X) > 1e-9 or abs(delta.Y) > 1e-9:\r\n ElementTransformUtils.MoveElement(doc, vp.Id, delta)\r\n created.append(vp)\r\n except Exception as ex:\r\n errors.append('Viewport {0}/{1}: {2}'.format(sn, vn, _exc_str(ex)))\r\n finally:\r\n TransactionManager.Instance.TransactionTaskDone()\r\n OUT = created + (['ERRORES:'] + errors if errors else [])\r\n\r\n# --- RÜM: mensaje de cierre (URL en rum_platform_url.py) ---\r\ntry:\r\n import sys as _rum_sys\r\n _rum_root = r'c:\\RUM_Platform\\RUM_Tools\\Dynamo_Routines'\r\n if _rum_root not in _rum_sys.path:\r\n _rum_sys.path.insert(0, _rum_root)\r\n import rum_finalize as _rum_fin\r\n OUT = _rum_fin.apply(OUT)\r\nexcept Exception:\r\n pass\r\n", "Engine": "CPython3", "VariableInputPorts": true, "Id": "0d18990eac7c48e9a529f3d1f63cb71e", "NodeType": "PythonScriptNode", "Inputs": [ { "Id": "0fe7e02e61554f43b8b8d403da316b28", "Name": "IN[0]", "Description": "Input #0", "UsingDefaultValue": false, "Level": 2, "UseLevels": false, "KeepListStructure": false }, { "Id": "5a93b68350e14495b9dd40ce03f47211", "Name": "IN[1]", "Description": "Input #1", "UsingDefaultValue": false, "Level": 2, "UseLevels": false, "KeepListStructure": false } ], "Outputs": [ { "Id": "9c2af7dcddea4c9dbb4de76f672180f2", "Name": "OUT", "Description": "Result of the python script", "UsingDefaultValue": false, "Level": 2, "UseLevels": false, "KeepListStructure": false } ], "Replication": "Disabled", "Description": "Runs an embedded Python script." }, { "ConcreteType": "CoreNodeModels.Input.Filename, CoreNodeModels", "Id": "23caef1ad90249449f1a983a7a2f198b", "NodeType": "ExtensionNode", "Inputs": [], "Outputs": [ { "Id": "272a2fe57bfd452cbaa690019a961ad1", "Name": "", "Description": "File Path", "UsingDefaultValue": false, "Level": 2, "UseLevels": false, "KeepListStructure": false } ], "Replication": "Disabled", "Description": "Allows you to select a file on the system and returns its file path", "HintPath": "c:\\\\RUM_Platform\\\\RUM_Tools\\\\Dynamo_Routines\\\\02_place_views_on_sheets\\\\RUM_template_viewports.xlsx", "InputValue": ".\\\\RUM_template_viewports.xlsx" }, { "ConcreteType": "Dynamo.Graph.Nodes.ZeroTouch.DSFunction, DynamoCore", "Id": "ec4dd2d362e04ab98cd7babaeb3c11cc", "NodeType": "FunctionNode", "Inputs": [ { "Id": "8fec46a5da4f4b68aad8e589940c82b1", "Name": "file", "Description": "var", "UsingDefaultValue": false, "Level": 2, "UseLevels": false, "KeepListStructure": false }, { "Id": "7bc9d9d1cedc4f8c876f39071957e92a", "Name": "sheetName", "Description": "string", "UsingDefaultValue": false, "Level": 2, "UseLevels": false, "KeepListStructure": false }, { "Id": "cce8d1bf748e4e75871e3facf8d34c36", "Name": "readAsStrings", "Description": "bool\nDefault value : false", "UsingDefaultValue": true, "Level": 2, "UseLevels": false, "KeepListStructure": false }, { "Id": "417a8c34b029420c9d896751d7f1947f", "Name": "showExcel", "Description": "bool\nDefault value : true", "UsingDefaultValue": true, "Level": 2, "UseLevels": false, "KeepListStructure": false } ], "Outputs": [ { "Id": "91537318aa13445aa9168c17f09d74d9", "Name": "var[][]", "Description": "var[][]", "UsingDefaultValue": false, "Level": 2, "UseLevels": false, "KeepListStructure": false } ], "FunctionSignature": "DSOffice.Data.ImportExcel@var,string,bool,bool", "Replication": "Auto", "Description": "Data.ImportExcel (file: var, sheetName: string, readAsStrings: bool = false, showExcel: bool = true): var[][]" }, { "ConcreteType": "CoreNodeModels.Input.StringInput, CoreNodeModels", "Id": "e96f85cc36334ecaaddba440131bf7c9", "NodeType": "StringInputNode", "Inputs": [], "Outputs": [ { "Id": "5e6cfee3577d43eabd8699f8b87379f0", "Name": "", "Description": "String", "UsingDefaultValue": false, "Level": 2, "UseLevels": false, "KeepListStructure": false } ], "Replication": "Disabled", "Description": "Creates a string", "InputValue": "Viewports" }, { "ConcreteType": "CoreNodeModels.Input.FileObject, CoreNodeModels", "Id": "b8344f24f30c4658af5831d90fc59e45", "NodeType": "ExtensionNode", "Inputs": [ { "Id": "b6dd668e3ed54171b3392792a02846f1", "Name": "path", "Description": "Path to the file.", "UsingDefaultValue": false, "Level": 2, "UseLevels": false, "KeepListStructure": false } ], "Outputs": [ { "Id": "985c22f6579b47c69f4a162f0d5cdfcf", "Name": "file", "Description": "File object", "UsingDefaultValue": false, "Level": 2, "UseLevels": false, "KeepListStructure": false } ], "Replication": "Disabled", "Description": "Creates a file object from the given path" } ], "Connectors": [ { "Start": "272a2fe57bfd452cbaa690019a961ad1", "End": "b6dd668e3ed54171b3392792a02846f1", "Id": "e7dd1b20a7084800b12c7e691a550cbb", "IsHidden": "False" }, { "Start": "91537318aa13445aa9168c17f09d74d9", "End": "0fe7e02e61554f43b8b8d403da316b28", "Id": "a8897cbca50342f0afd626ea4283632d", "IsHidden": "False" }, { "Start": "5e6cfee3577d43eabd8699f8b87379f0", "End": "7bc9d9d1cedc4f8c876f39071957e92a", "Id": "6eac21a13b764e2786344d52e8047323", "IsHidden": "False" }, { "Start": "985c22f6579b47c69f4a162f0d5cdfcf", "End": "8fec46a5da4f4b68aad8e589940c82b1", "Id": "60f8522dd1fa40f5994afda4f5aeb06e", "IsHidden": "False" } ], "Dependencies": [], "NodeLibraryDependencies": [ { "Name": "RUM_template_viewports.xlsx", "ReferenceType": "External", "Nodes": [ "23caef1ad90249449f1a983a7a2f198b" ] } ], "EnableLegacyPolyCurveBehavior": true, "Thumbnail": "", "GraphDocumentationURL": null, "ExtensionWorkspaceData": [ { "ExtensionGuid": "28992e1d-abb9-417f-8b1b-05e053bee670", "Name": "Properties", "Version": "3.3", "Data": {} }, { "ExtensionGuid": "DFBD9CC0-DB40-457A-939E-8C8555555A9D", "Name": "Generative Design", "Version": "8.2", "Data": {} } ], "Author": "", "Linting": { "activeLinter": "None", "activeLinterId": "7b75fb44-43fd-4631-a878-29f4d5d8399a", "warningCount": 0, "errorCount": 0 }, "Bindings": [], "View": { "Dynamo": { "ScaleFactor": 1, "HasRunWithoutCrash": true, "IsVisibleInDynamoLibrary": true, "Version": "3.3.0.6316", "RunType": "Manual", "RunPeriod": "1000" }, "Camera": { "Name": "_Background Preview", "EyeX": -18.535983562469482, "EyeY": 23.32427215576172, "EyeZ": 49.833648681640625, "LookX": 12, "LookY": -13, "LookZ": -58, "UpX": 0, "UpY": 1, "UpZ": 0 }, "ConnectorPins": [], "NodeViews": [ { "Id": "0d18990eac7c48e9a529f3d1f63cb71e", "Name": "RÜM", "IsSetAsInput": false, "IsSetAsOutput": false, "Excluded": false, "ShowGeometry": true, "X": 862.6165069225223, "Y": 530.3814713301231 }, { "Id": "23caef1ad90249449f1a983a7a2f198b", "Name": "File Path", "IsSetAsInput": false, "IsSetAsOutput": false, "Excluded": false, "ShowGeometry": true, "X": -8.315159315298331, "Y": 291.5914154333133 }, { "Id": "ec4dd2d362e04ab98cd7babaeb3c11cc", "Name": "Data.ImportExcel", "IsSetAsInput": false, "IsSetAsOutput": false, "Excluded": false, "ShowGeometry": true, "X": 514.6944472774601, "Y": 387.99581750267964 }, { "Id": "7153d68f970a4ddd9b0d3099f0d262ad", "Name": "Familia de Plano/Solapa", "IsSetAsInput": false, "IsSetAsOutput": false, "Excluded": false, "ShowGeometry": true, "X": -149.41137425768665, "Y": 593.1960401139188 }, { "Id": "e96f85cc36334ecaaddba440131bf7c9", "Name": "String", "IsSetAsInput": false, "IsSetAsOutput": false, "Excluded": false, "ShowGeometry": true, "X": 116.52185745895031, "Y": 432.9340341699957 }, { "Id": "b8344f24f30c4658af5831d90fc59e45", "Name": "File From Path", "IsSetAsInput": false, "IsSetAsOutput": false, "Excluded": false, "ShowGeometry": true, "X": 277.8292992058231, "Y": 292.4490701977819 } ], "Annotations": [], "X": 450.46757606535687, "Y": 65.63039603291628, "Zoom": 0.7551205330692716 } }