# 📚 BIBLIOTECA MAESTRA DE AUTOMATIZACIÓN REVIT - IXA IA ## Guía Completa de Códigos y Flujos de Trabajo BIM --- ## 🎯 ÍNDICE GENERAL 1. [FLUJO DE TRABAJO EN 4 FASES](#parte-1-flujo-de-trabajo-en-4-fases) 2. [CATÁLOGO DE CÓDIGOS POR CATEGORÍA](#parte-2-catálogo-de-códigos) 3. [CÓDIGOS DE DOCUMENTACIÓN ARQUITECTÓNICA](#parte-3-documentación-arquitectónica) 4. [CÓDIGOS AUXILIARES DE CONSULTA](#parte-4-códigos-auxiliares) 5. [NOTAS TÉCNICAS](#parte-5-notas-técnicas) --- # PARTE 1: FLUJO DE TRABAJO EN 4 FASES ## 📋 Secuencia de Construcción BIM El modelado de un edificio sigue una secuencia lógica que replica el proceso constructivo real: ``` ┌─────────────────────────────────────────────────────────────────┐ │ FASE 1: CIMENTACIÓN DEL PROYECTO │ │ ├── 1.1 Crear Rejillas (sistema de coordenadas) │ │ ├── 1.2 Acotar Rejillas (documentación) │ │ └── 1.3 Crear Niveles (estructura vertical) │ ├─────────────────────────────────────────────────────────────────┤ │ FASE 2: ESTRUCTURA DEL NIVEL BASE │ │ ├── 2.1 Identificar familias (obtener TypeIds) │ │ ├── 2.2 Colocar Zapatas (cimentación) │ │ ├── 2.3 Colocar Pilares (elementos verticales) │ │ └── 2.4 Crear Vigas (elementos horizontales) │ ├─────────────────────────────────────────────────────────────────┤ │ FASE 3: CONSTRUCCIÓN VERTICAL Y MASIVA │ │ ├── 3.1 Replicar estructura en niveles superiores │ │ └── 3.2 Crear Losas de entrepiso │ ├─────────────────────────────────────────────────────────────────┤ │ FASE 4: CERRAMIENTOS Y FACHADA │ │ ├── 4.1 Crear Muros Cortina perimetrales │ │ └── 4.2 Crear Muros básicos interiores │ └─────────────────────────────────────────────────────────────────┘ ``` ### ⚠️ DEPENDENCIAS CRÍTICAS | Antes de crear... | Debe existir... | |-------------------|-----------------| | Zapatas | Rejillas + Nivel de cimentación | | Pilares | Zapatas + Dos niveles (base y superior) | | Vigas | Pilares + Nivel de referencia | | Losas | Vigas + Nivel de colocación | | Muros Cortina | Estructura completa + Niveles | --- # PARTE 2: CATÁLOGO DE CÓDIGOS ## 📐 2.1 GESTIÓN DE REJILLAS Y EJES ### CÓDIGO 1.1: CREAR REJILLAS PARAMÉTRICAS ¿CUÁNDO USARLO? Al iniciar cualquier proyecto nuevo - es el PRIMER paso. ¿QUÉ HACE? Crea el sistema de ejes ortogonales (A,B,C... y 1,2,3...) que define la geometría base del edificio. PARÁMETROS A MODIFICAR: ```csharp string[] nombresVerticales = {"A", "B", "C", "D", "E", "F"}; double[] posicionesVerticales = {0, 3, 6.5, 10.3, 12.8, 15.6}; // metros string[] nombresHorizontales = {"1", "2", "3", "4", "5", "6"}; double[] posicionesHorizontales = {0, 3, 6.5, 10.3, 13.1, 16.3}; // metros double longitudRejilla = 25; // metros double inicioRejilla = -5; // metros (negativo = extensión hacia atrás) ``` CÓDIGO COMPLETO: ```csharp try { var doc = document; // CONFIGURACIÓN PARAMÉTRICA string[] nombresVerticales = {"A", "B", "C", "D", "E", "F"}; double[] posicionesVerticales = {0, 3, 6.5, 10.3, 12.8, 15.6}; string[] nombresHorizontales = {"1", "2", "3", "4", "5", "6"}; double[] posicionesHorizontales = {0, 3, 6.5, 10.3, 13.1, 16.3}; double longitudRejilla = 25 3.28084; double inicioRejilla = -5 3.28084; string resultado = "═══ REJILLAS VERTICALES ═══\n"; for(int i = 0; i < nombresVerticales.Length; i++) { double posX = posicionesVerticales[i] 3.28084; XYZ startPoint = new XYZ(posX, inicioRejilla, 0); XYZ endPoint = new XYZ(posX, inicioRejilla + longitudRejilla, 0); Line gridLine = Line.CreateBound(startPoint, endPoint); Grid grid = Grid.Create(doc, gridLine); grid.Name = nombresVerticales[i]; resultado += "✓ " + nombresVerticales[i] + " en X=" + posicionesVerticales[i] + "m\n"; } resultado += "\n═══ REJILLAS HORIZONTALES ═══\n"; for(int j = 0; j < nombresHorizontales.Length; j++) { double posY = posicionesHorizontales[j] 3.28084; XYZ startPoint = new XYZ(inicioRejilla, posY, 0); XYZ endPoint = new XYZ(inicioRejilla + longitudRejilla, posY, 0); Line gridLine = Line.CreateBound(startPoint, endPoint); Grid grid = Grid.Create(doc, gridLine); grid.Name = nombresHorizontales[j]; resultado += "✓ " + nombresHorizontales[j] + " en Y=" + posicionesHorizontales[j] + "m\n"; } return resultado; } catch (Exception ex) { return "❌ Error: " + ex.Message; } ``` --- ### CÓDIGO 1.2: ACOTAR REJILLAS AUTOMÁTICAMENTE ¿CUÁNDO USARLO? Después de crear las rejillas, para documentar las distancias. ¿QUÉ HACE? Crea cotas lineales entre rejillas consecutivas: - Rejillas verticales → Cotas en la parte SUPERIOR - Rejillas horizontales → Cotas en el lado DERECHO CÓDIGO COMPLETO: ```csharp try { var doc = document; var uidoc = new UIDocument(doc); var activeView = uidoc.ActiveView; var collector = new FilteredElementCollector(doc, activeView.Id) .OfClass(typeof(Grid)); // Obtener tipo de cota var dimTypeCollector = new FilteredElementCollector(doc) .OfClass(typeof(DimensionType)); DimensionType dimType = null; foreach(Element elem in dimTypeCollector) { var dt = elem as DimensionType; if(dt != null && dt.StyleType == DimensionStyleType.Linear) { dimType = dt; break; } } // Separar rejillas por orientación var rejillasVerticales = new List<Grid>(); var rejillasHorizontales = new List<Grid>(); foreach(Element elem in collector) { var grid = elem as Grid; if(grid != null) { Line curve = grid.Curve as Line; XYZ direction = curve.Direction.Normalize(); if(Math.Abs(direction.Y) > Math.Abs(direction.X)) rejillasVerticales.Add(grid); else rejillasHorizontales.Add(grid); } } // Ordenar rejillas rejillasVerticales = rejillasVerticales.OrderBy(g => { Line curve = g.Curve as Line; return curve.GetEndPoint(0).X; }).ToList(); rejillasHorizontales = rejillasHorizontales.OrderBy(g => { Line curve = g.Curve as Line; return curve.GetEndPoint(0).Y; }).ToList(); string resultado = "═══ ACOTACIÓN DE REJILLAS ═══\n"; int cotasCreadas = 0; double offsetY = 5 3.28084; double offsetX = 5 3.28084; // Acotar rejillas verticales en parte superior for(int i = 0; i < rejillasVerticales.Count - 1; i++) { var ref1 = new Reference(rejillasVerticales[i]); var ref2 = new Reference(rejillasVerticales[i + 1]); var references = new ReferenceArray(); references.Append(ref1); references.Append(ref2); var curve1 = rejillasVerticales[i].Curve as Line; var curve2 = rejillasVerticales[i + 1].Curve as Line; var pt1 = curve1.GetEndPoint(1); var pt2 = curve2.GetEndPoint(1); var dimLine = Line.CreateBound( new XYZ(pt1.X, pt1.Y + offsetY, 0), new XYZ(pt2.X, pt2.Y + offsetY, 0) ); doc.Create.NewDimension(activeView, dimLine, references); cotasCreadas++; resultado += "✓ Cota: " + rejillasVerticales[i].Name + "-" + rejillasVerticales[i+1].Name + "\n"; } // Acotar rejillas horizontales en lado derecho for(int i = 0; i < rejillasHorizontales.Count - 1; i++) { var ref1 = new Reference(rejillasHorizontales[i]); var ref2 = new Reference(rejillasHorizontales[i + 1]); var references = new ReferenceArray(); references.Append(ref1); references.Append(ref2); var curve1 = rejillasHorizontales[i].Curve as Line; var curve2 = rejillasHorizontales[i + 1].Curve as Line; var pt1 = curve1.GetEndPoint(1); var pt2 = curve2.GetEndPoint(1); var dimLine = Line.CreateBound( new XYZ(pt1.X + offsetX, pt1.Y, 0), new XYZ(pt2.X + offsetX, pt2.Y, 0) ); doc.Create.NewDimension(activeView, dimLine, references); cotasCreadas++; resultado += "✓ Cota: " + rejillasHorizontales[i].Name + "-" + rejillasHorizontales[i+1].Name + "\n"; } return resultado + "\n✅ Total: " + cotasCreadas + " cotas creadas"; } catch (Exception ex) { return "❌ Error: " + ex.Message; } ``` --- ### CÓDIGO 1.3: RENOMBRAR REJILLAS EN MASA ¿CUÁNDO USARLO? Para estandarizar nomenclatura en proyectos importados. CÓDIGO COMPLETO: ```csharp try { var doc = document; // Diccionario de renombrado: nombreActual -> nombreNuevo var renombrado = new Dictionary<string, string> { {"Grid 1", "A"}, {"Grid 2", "B"}, {"Grid 3", "C"}, {"Axis 1", "1"}, {"Axis 2", "2"} }; var collector = new FilteredElementCollector(doc) .OfClass(typeof(Grid)); int renombrados = 0; string resultado = "═══ RENOMBRADO DE REJILLAS ═══\n"; foreach(Element elem in collector) { var grid = elem as Grid; if(grid != null && renombrado.ContainsKey(grid.Name)) { string nombreAnterior = grid.Name; grid.Name = renombrado[nombreAnterior]; resultado += "✓ " + nombreAnterior + " → " + grid.Name + "\n"; renombrados++; } } return resultado + "\n✅ " + renombrados + " rejillas renombradas"; } catch (Exception ex) { return "❌ Error: " + ex.Message; } ``` --- ## 📏 2.2 GESTIÓN DE NIVELES ### CÓDIGO 2.1: CREAR NIVEL INDIVIDUAL ¿CUÁNDO USARLO? Para crear un nivel específico (ej: Subsuelo, Mezzanine, Azotea). PARÁMETROS A MODIFICAR: ```csharp string nombreNivelBase = "Nivel 1"; // Nivel de referencia existente string nombreNuevoNivel = "Subsuelo"; // Nombre del nuevo nivel double distanciaMetros = -3.0; // Negativo=abajo, Positivo=arriba ``` CÓDIGO COMPLETO: ```csharp try { var doc = document; string nombreNivelBase = "Nivel 1"; string nombreNuevoNivel = "Subsuelo"; double distanciaMetros = -3.0; var levelCollector = new FilteredElementCollector(doc) .OfClass(typeof(Level)); Level nivelBase = null; foreach(Element elem in levelCollector) { var level = elem as Level; if(level != null && level.Name.Contains(nombreNivelBase)) { nivelBase = level; break; } } if(nivelBase == null) return "❌ No se encontró el nivel '" + nombreNivelBase + "'"; double distanciaPies = distanciaMetros 3.28084; double elevacionNueva = nivelBase.Elevation + distanciaPies; Level nuevoNivel = Level.Create(doc, elevacionNueva); nuevoNivel.Name = nombreNuevoNivel; return "✅ Nivel '" + nombreNuevoNivel + "' creado\n" + "Elevación: " + (elevacionNueva/3.28084).ToString("F2") + "m\n" + "Offset desde " + nombreNivelBase + ": " + distanciaMetros.ToString("F2") + "m"; } catch (Exception ex) { return "❌ Error: " + ex.Message; } ``` --- ### CÓDIGO 2.2: CREAR MÚLTIPLES NIVELES CON SEPARACIÓN UNIFORME *¿CUÁNDO USARLO?** Para edificios con entrepisos de altura constante. CÓDIGO COMPLETO: ```csharp try { var doc = document; string nombreNivelBase = "Nivel 1"; string[] nombresNiveles = {"Nivel 2", "Nivel 3", "Nivel 4", "Nivel 5"}; double separacionMetros = 3.0; var levelCollector = new FilteredElementCollector(doc) .OfClass(typeof(Level)); Level nivelBase = null; var nivelesExistentes = new HashSet<string>(); foreach(Element elem in levelCollector) { var level = elem as Level; if(level != null) { nivelesExistentes.Add(level.Name); if(level.Name.Contains(nombreNivelBase)) nivelBase = level; } } if(nivelBase == null) return "❌ No se encontró el nivel base"; double separacionPies = separacionMetros 3.28084; double elevacionBase = nivelBase.Elevation; string resultado = "═══ NIVELES CREADOS ═══\n"; int creados = 0; for(int i = 0; i < nombresNiveles.Length; i++) { if(!nivelesExistentes.Contains(nombresNiveles[i])) { double elevacion = elevacionBase + ((i + 1) separacionPies); Level nuevoNivel = Level.Create(doc, elevacion); nuevoNivel.Name = nombresNiveles[i]; resultado += "✓ " + nombresNiveles[i] + " (" + (elevacion/3.28084).ToString("F2") + "m)\n"; creados++; } else { resultado += "⚠️ " + nombresNiveles[i] + " ya existe\n"; } } return resultado + "\n✅ " + creados + " niveles creados"; } catch (Exception ex) { return "❌ Error: " + ex.Message; } ``` --- ### CÓDIGO 2.3: CREAR NIVELES CON SEPARACIONES VARIABLES ¿CUÁNDO USARLO? Para edificios con alturas diferentes por nivel (comercial + residencial, dobles alturas). CÓDIGO COMPLETO: ```csharp try { var doc = document; string nombreNivelBase = "Nivel 1"; // NombreNivel -> Altura desde nivel base (metros) var nivelesConfig = new Dictionary<string, double> { {"Mezzanine", 1.8}, {"Nivel 2", 5.0}, {"Nivel 3", 8.0}, {"Nivel 4", 11.0}, {"Azotea", 14.5} }; var levelCollector = new FilteredElementCollector(doc) .OfClass(typeof(Level)); Level nivelBase = null; foreach(Element elem in levelCollector) { var level = elem as Level; if(level != null && level.Name.Contains(nombreNivelBase)) { nivelBase = level; break; } } if(nivelBase == null) return "❌ No se encontró el nivel base"; string resultado = "═══ NIVELES CON ALTURAS VARIABLES ═══\n"; int creados = 0; foreach(var kvp in nivelesConfig) { double elevacionPies = nivelBase.Elevation + (kvp.Value 3.28084); Level nuevoNivel = Level.Create(doc, elevacionPies); nuevoNivel.Name = kvp.Key; resultado += "✓ " + kvp.Key + " (+" + kvp.Value.ToString("F2") + "m desde base)\n"; creados++; } return resultado + "\n✅ " + creados + " niveles creados"; } catch (Exception ex) { return "❌ Error: " + ex.Message; } ``` --- ### CÓDIGO 2.4: LISTAR Y ANALIZAR NIVELES EXISTENTES *¿CUÁNDO USARLO?** Para auditoría, documentación o antes de crear nuevos niveles. CÓDIGO COMPLETO: ```csharp try { var doc = document; var levelCollector = new FilteredElementCollector(doc) .OfClass(typeof(Level)) .Cast<Level>() .OrderBy(l => l.Elevation); string resultado = "═══ ANÁLISIS DE NIVELES ═══\n\n"; resultado += String.Format("{0,-20} {1,-15} {2,-10}\n", "Nombre", "Elevación (m)", "ID"); resultado += new string('─', 50) + "\n"; Level nivelAnterior = null; foreach(Level level in levelCollector) { double elevacionMetros = level.Elevation / 3.28084; resultado += String.Format("{0,-20} {1,15:F3} {2,-10}\n", level.Name, elevacionMetros, level.Id.IntegerValue); if(nivelAnterior != null) { double distancia = (level.Elevation - nivelAnterior.Elevation) / 3.28084; resultado += " ↕ Distancia desde " + nivelAnterior.Name + ": " + distancia.ToString("F3") + "m\n"; } nivelAnterior = level; } return resultado; } catch (Exception ex) { return "❌ Error: " + ex.Message; } ``` --- ## 🏗️ 2.3 ELEMENTOS ESTRUCTURALES - CIMENTACIÓN ### CÓDIGO 3.1: COLOCAR ZAPATAS EN INTERSECCIONES DE REJILLA ¿CUÁNDO USARLO? Después de crear rejillas y niveles, para la cimentación completa. ⚠️ PRERREQUISITO: Obtener el TypeId de la zapata usando el código auxiliar de búsqueda. PARÁMETROS A MODIFICAR: ```csharp string nombreNivel = "Subsuelo"; int zapataTypeId = 166935; // ¡OBTENER CON CÓDIGO AUXILIAR! double[] posicionesVerticales = {0, 3, 6.5, 10.3, 12.8, 15.6}; double[] posicionesHorizontales = {0, 3, 6.5, 10.3, 13.1, 16.3}; ``` CÓDIGO COMPLETO: ```csharp try { var doc = document; string nombreNivel = "Subsuelo"; int zapataTypeId = 166935; // CAMBIAR por tu ID double[] posicionesVerticales = {0, 3, 6.5, 10.3, 12.8, 15.6}; string[] nombresVerticales = {"A", "B", "C", "D", "E", "F"}; double[] posicionesHorizontales = {0, 3, 6.5, 10.3, 13.1, 16.3}; string[] nombresHorizontales = {"1", "2", "3", "4", "5", "6"}; var levelCollector = new FilteredElementCollector(doc) .OfClass(typeof(Level)); Level nivel = null; foreach(Element elem in levelCollector) { var lv = elem as Level; if(lv != null && lv.Name == nombreNivel) { nivel = lv; break; } } if(nivel == null) return "❌ Nivel '" + nombreNivel + "' no encontrado"; var zapataType = doc.GetElement(new ElementId(zapataTypeId)) as FamilySymbol; if(zapataType == null) return "❌ Zapata con ID " + zapataTypeId + " no encontrada"; if(!zapataType.IsActive) zapataType.Activate(); string resultado = "═══ ZAPATAS CREADAS ═══\n"; int zapatasCreadas = 0; for(int i = 0; i < posicionesVerticales.Length; i++) { for(int j = 0; j < posicionesHorizontales.Length; j++) { double xPies = posicionesVerticales[i] 3.28084; double yPies = posicionesHorizontales[j] 3.28084; var ubicacion = new XYZ(xPies, yPies, 0); var zapata = doc.Create.NewFamilyInstance( ubicacion, zapataType, nivel, StructuralType.Footing ); zapatasCreadas++; string coord = nombresVerticales[i] + nombresHorizontales[j]; resultado += "✓ " + coord + " (ID:" + zapata.Id.IntegerValue + ")\n"; } } return resultado + "\n✅ Total: " + zapatasCreadas + " zapatas"; } catch (Exception ex) { return "❌ Error: " + ex.Message; } ``` --- ## 🏛️ 2.4 ELEMENTOS ESTRUCTURALES - VERTICALES (PILARES) ### CÓDIGO 4.1: COLOCAR PILARES EN INTERSECCIONES ¿CUÁNDO USARLO? Después de colocar zapatas, para crear los elementos verticales. CÓDIGO COMPLETO: ```csharp try { var doc = document; string nombreNivelBase = "Subsuelo"; string nombreNivelSuperior = "Nivel 1"; int pilarTypeId = 11775; // CAMBIAR por tu ID double[] posicionesVerticales = {0, 3, 6.5, 10.3, 12.8, 15.6}; string[] nombresVerticales = {"A", "B", "C", "D", "E", "F"}; double[] posicionesHorizontales = {0, 3, 6.5, 10.3, 13.1, 16.3}; string[] nombresHorizontales = {"1", "2", "3", "4", "5", "6"}; var levelCollector = new FilteredElementCollector(doc) .OfClass(typeof(Level)); Level nivelBase = null; Level nivelSuperior = null; foreach(Element elem in levelCollector) { var level = elem as Level; if(level != null) { if(level.Name == nombreNivelBase) nivelBase = level; if(level.Name.Contains(nombreNivelSuperior)) nivelSuperior = level; } } if(nivelBase == null || nivelSuperior == null) return "❌ No se encontraron los niveles especificados"; var pilarType = doc.GetElement(new ElementId(pilarTypeId)) as FamilySymbol; if(pilarType == null) return "❌ Pilar con ID " + pilarTypeId + " no encontrado"; if(!pilarType.IsActive) pilarType.Activate(); string resultado = "═══ PILARES CREADOS ═══\n"; int pilaresCreados = 0; for(int i = 0; i < posicionesVerticales.Length; i++) { for(int j = 0; j < posicionesHorizontales.Length; j++) { double xPies = posicionesVerticales[i] 3.28084; double yPies = posicionesHorizontales[j] 3.28084; var ubicacion = new XYZ(xPies, yPies, 0); var pilar = doc.Create.NewFamilyInstance( ubicacion, pilarType, nivelBase, StructuralType.Column ); pilar.get_Parameter(BuiltInParameter.FAMILY_BASE_LEVEL_PARAM).Set(nivelBase.Id); pilar.get_Parameter(BuiltInParameter.FAMILY_BASE_LEVEL_OFFSET_PARAM).Set(0); pilar.get_Parameter(BuiltInParameter.FAMILY_TOP_LEVEL_PARAM).Set(nivelSuperior.Id); pilar.get_Parameter(BuiltInParameter.FAMILY_TOP_LEVEL_OFFSET_PARAM).Set(0); pilaresCreados++; string coord = nombresVerticales[i] + nombresHorizontales[j]; resultado += "✓ " + coord + " (ID:" + pilar.Id.IntegerValue + ")\n"; } } double altura = (nivelSuperior.Elevation - nivelBase.Elevation) / 3.28084; return resultado + "\n✅ Total: " + pilaresCreados + " pilares\nAltura: " + altura.ToString("F2") + "m"; } catch (Exception ex) { return "❌ Error: " + ex.Message; } ``` --- ## 🔗 2.5 ELEMENTOS ESTRUCTURALES - HORIZONTALES (VIGAS) ### CÓDIGO 5.1: CREAR RED COMPLETA DE VIGAS ¿CUÁNDO USARLO? Después de colocar pilares, para conectarlos horizontalmente. CÓDIGO COMPLETO: ```csharp try { var doc = document; string nombreNivel = "Nivel 1"; int vigaTypeId = 163249; // CAMBIAR por tu ID double[] posicionesVerticales = {0, 3, 6.5, 10.5}; double[] posicionesHorizontales = {0, 2.5, 5.3, 8.5}; var nivel = new FilteredElementCollector(doc) .OfClass(typeof(Level)) .Cast<Level>() .FirstOrDefault(l => l.Name == nombreNivel); if(nivel == null) return "❌ Nivel '" + nombreNivel + "' no encontrado"; var vigaType = doc.GetElement(new ElementId(vigaTypeId)) as FamilySymbol; if(vigaType == null) return "❌ Viga con ID " + vigaTypeId + " no encontrada"; if(!vigaType.IsActive) vigaType.Activate(); string resultado = "═══ VIGAS CREADAS ═══\n"; int vigasCreadas = 0; double zPies = nivel.Elevation; // Vigas horizontales (paralelas a X) resultado += "Dirección X:\n"; for(int j = 0; j < posicionesHorizontales.Length; j++) { double yPies = posicionesHorizontales[j] 3.28084; for(int i = 0; i < posicionesVerticales.Length - 1; i++) { double x1 = posicionesVerticales[i] 3.28084; double x2 = posicionesVerticales[i + 1] 3.28084; var inicio = new XYZ(x1, yPies, zPies); var fin = new XYZ(x2, yPies, zPies); var linea = Line.CreateBound(inicio, fin); doc.Create.NewFamilyInstance(linea, vigaType, nivel, StructuralType.Beam); vigasCreadas++; } } // Vigas verticales (paralelas a Y) resultado += "Dirección Y:\n"; for(int i = 0; i < posicionesVerticales.Length; i++) { double xPies = posicionesVerticales[i] 3.28084; for(int j = 0; j < posicionesHorizontales.Length - 1; j++) { double y1 = posicionesHorizontales[j] 3.28084; double y2 = posicionesHorizontales[j + 1] 3.28084; var inicio = new XYZ(xPies, y1, zPies); var fin = new XYZ(xPies, y2, zPies); var linea = Line.CreateBound(inicio, fin); doc.Create.NewFamilyInstance(linea, vigaType, nivel, StructuralType.Beam); vigasCreadas++; } } return resultado + "\n✅ Total: " + vigasCreadas + " vigas en " + nombreNivel; } catch (Exception ex) { return "❌ Error: " + ex.Message; } ``` --- ## 🏢 2.6 ELEMENTOS DE CERRAMIENTO ### CÓDIGO 6.1: CREAR LOSAS DE ENTREPISO RECTANGULARES ¿CUÁNDO USARLO? Después de crear la estructura de vigas. CÓDIGO COMPLETO: ```csharp try { var doc = document; string[] nombresNiveles = {"Nivel 1", "Nivel 2", "Nivel 3"}; // Coordenadas del rectángulo (metros) double xMin = 0; double xMax = 15.6; double yMin = 0; double yMax = 16.3; // Convertir a pies double xMinPies = xMin 3.28084; double xMaxPies = xMax 3.28084; double yMinPies = yMin 3.28084; double yMaxPies = yMax 3.28084; var levelCollector = new FilteredElementCollector(doc) .OfClass(typeof(Level)); var niveles = new List<Level>(); foreach(string nombreNivel in nombresNiveles) { foreach(Element elem in levelCollector) { var level = elem as Level; if(level != null && level.Name.Contains(nombreNivel)) { niveles.Add(level); break; } } } var floorType = new FilteredElementCollector(doc) .OfClass(typeof(FloorType)) .Cast<FloorType>() .FirstOrDefault(ft => !ft.Name.ToLower().Contains("foundation")); if(floorType == null) return "❌ No se encontró tipo de losa"; var p1 = new XYZ(xMinPies, yMinPies, 0); var p2 = new XYZ(xMaxPies, yMinPies, 0); var p3 = new XYZ(xMaxPies, yMaxPies, 0); var p4 = new XYZ(xMinPies, yMaxPies, 0); string resultado = "═══ LOSAS CREADAS ═══\n"; int losasCreadas = 0; foreach(Level nivel in niveles) { var curves = new List<Curve> { Line.CreateBound(p1, p2), Line.CreateBound(p2, p3), Line.CreateBound(p3, p4), Line.CreateBound(p4, p1) }; var curveLoop = CurveLoop.Create(curves); var profile = new List<CurveLoop> { curveLoop }; var floor = Floor.Create(doc, profile, floorType.Id, nivel.Id); losasCreadas++; resultado += "✓ Losa en " + nivel.Name + " (ID:" + floor.Id.IntegerValue + ")\n"; } double area = (xMax - xMin) (yMax - yMin); return resultado + "\n✅ " + losasCreadas + " losas\nÁrea c/u: " + area.ToString("F2") + "m²"; } catch (Exception ex) { return "❌ Error: " + ex.Message; } ``` --- ### CÓDIGO 6.3: CREAR MUROS CORTINA PERIMETRALES *¿CUÁNDO USARLO?** Para crear fachadas de vidrio en todo el perímetro. CÓDIGO COMPLETO: ```csharp try { var doc = document; string[] nombresNiveles = {"Nivel 1", "Nivel 2", "Nivel 3", "Nivel 4"}; double xA = 0 3.28084; double xF = 15.6 3.28084; double y1 = 0 3.28084; double y6 = 16.3 3.28084; var levelCollector = new FilteredElementCollector(doc) .OfClass(typeof(Level)); var niveles = new List<Level>(); foreach(string nombreNivel in nombresNiveles) { foreach(Element elem in levelCollector) { var level = elem as Level; if(level != null && level.Name.Contains(nombreNivel)) { niveles.Add(level); break; } } } var curtainWallType = new FilteredElementCollector(doc) .OfClass(typeof(WallType)) .Cast<WallType>() .FirstOrDefault(wt => wt.Name.ToLower().Contains("cortina") || wt.Name.ToLower().Contains("curtain")); if(curtainWallType == null) return "❌ No se encontró tipo de muro cortina"; var esquinas = new XYZ[] { new XYZ(xA, y1, 0), new XYZ(xF, y1, 0), new XYZ(xF, y6, 0), new XYZ(xA, y6, 0) }; string resultado = "═══ MUROS CORTINA ═══\n"; int murosCreados = 0; for(int i = 0; i < niveles.Count - 1; i++) { Level nivelBase = niveles[i]; Level nivelSuperior = niveles[i + 1]; double altura = nivelSuperior.Elevation - nivelBase.Elevation; string[] orientaciones = {"Sur", "Este", "Norte", "Oeste"}; for(int j = 0; j < 4; j++) { int nextIndex = (j + 1) % 4; var linea = Line.CreateBound(esquinas[j], esquinas[nextIndex]); Wall.Create(doc, linea, curtainWallType.Id, nivelBase.Id, altura, 0, false, false); murosCreados++; } resultado += "✓ 4 muros " + nivelBase.Name + "→" + nivelSuperior.Name + "\n"; } return resultado + "\n✅ Total: " + murosCreados + " muros cortina"; } catch (Exception ex) { return "❌ Error: " + ex.Message; } ``` --- ## 🔍 2.7 CONSULTA Y ANÁLISIS DE ELEMENTOS ### CÓDIGO 7.1: LISTAR FAMILIAS DISPONIBLES POR CATEGORÍA ¿CUÁNDO USARLO? ANTES de crear elementos, para obtener los TypeIds necesarios. CÓDIGO COMPLETO: ```csharp try { var doc = document; // CONFIGURAR CATEGORÍA A BUSCAR: BuiltInCategory categoria = BuiltInCategory.OST_StructuralColumns; // Otras opciones: // OST_StructuralFoundation (Zapatas) // OST_StructuralFraming (Vigas) // OST_Floors (Losas) // OST_Walls (Muros) // OST_Doors (Puertas) // OST_Windows (Ventanas) var collector = new FilteredElementCollector(doc) .OfClass(typeof(FamilySymbol)) .OfCategory(categoria); string resultado = "═══ FAMILIAS DISPONIBLES ═══\n\n"; resultado += String.Format("{0,-30} {1,-30} {2,-10}\n", "Familia", "Tipo", "ID"); resultado += new string('─', 75) + "\n"; int contador = 0; foreach(Element elem in collector) { var fs = elem as FamilySymbol; if(fs != null) { string familyName = fs.FamilyName; string typeName = fs.Name; int id = fs.Id.IntegerValue; resultado += String.Format("{0,-30} {1,-30} {2,-10}\n", familyName, typeName, id); contador++; } } return resultado + "\n✅ Total: " + contador + " tipos encontrados"; } catch (Exception ex) { return "❌ Error: " + ex.Message; } ``` --- ### CÓDIGO 7.2: ANALIZAR ELEMENTOS SELECCIONADOS ¿CUÁNDO USARLO? Para inspeccionar propiedades de elementos específicos. CÓDIGO COMPLETO: ```csharp try { var doc = document; var uidoc = new UIDocument(doc); var selection = uidoc.Selection; var selectedIds = selection.GetElementIds(); if(selectedIds.Count == 0) return "⚠️ No hay elementos seleccionados"; string resultado = "═══ ANÁLISIS DE ELEMENTOS SELECCIONADOS ═══\n\n"; foreach(ElementId id in selectedIds) { Element elem = doc.GetElement(id); if(elem != null) { resultado += "┌── ELEMENTO ID: " + id.IntegerValue + " ──┐\n"; resultado += "Categoría: " + (elem.Category != null ? elem.Category.Name : "N/A") + "\n"; resultado += "Clase: " + elem.GetType().Name + "\n"; resultado += "Nombre: " + elem.Name + "\n"; ElementId typeId = elem.GetTypeId(); if(typeId != ElementId.InvalidElementId) { ElementType elemType = doc.GetElement(typeId) as ElementType; if(elemType != null) { resultado += "Tipo: " + elemType.Name + " (ID: " + typeId.IntegerValue + ")\n"; if(elemType is FamilySymbol fs) { resultado += "Familia: " + fs.FamilyName + "\n"; } } } var levelParam = elem.get_Parameter(BuiltInParameter.INSTANCE_REFERENCE_LEVEL_PARAM); if(levelParam != null && levelParam.HasValue) { var nivel = doc.GetElement(levelParam.AsElementId()) as Level; if(nivel != null) resultado += "Nivel: " + nivel.Name + "\n"; } if(elem.Location is LocationPoint locPoint) { XYZ punto = locPoint.Point; resultado += "Ubicación: X=" + (punto.X/3.28084).ToString("F2") + "m, " + "Y=" + (punto.Y/3.28084).ToString("F2") + "m, " + "Z=" + (punto.Z/3.28084).ToString("F2") + "m\n"; } resultado += "\n"; } } return resultado + "✅ " + selectedIds.Count + " elementos analizados"; } catch (Exception ex) { return "❌ Error: " + ex.Message; } ``` --- ## 🎨 2.8 VISUALIZACIÓN Y GRÁFICOS ### CÓDIGO 8.1: COLOREAR ELEMENTOS POR CATEGORÍA ¿CUÁNDO USARLO? Para análisis visual, presentaciones o verificación de elementos. CÓDIGO COMPLETO: ```csharp try { var doc = document; var uidoc = new UIDocument(doc); var activeView = uidoc.ActiveView; var esquemaColor = new Dictionary<BuiltInCategory, Color> { {BuiltInCategory.OST_StructuralColumns, new Color(255, 0, 0)}, // Rojo {BuiltInCategory.OST_StructuralFraming, new Color(0, 0, 255)}, // Azul {BuiltInCategory.OST_StructuralFoundation, new Color(128, 128, 128)}, // Gris {BuiltInCategory.OST_Floors, new Color(200, 200, 150)}, // Beige {BuiltInCategory.OST_Walls, new Color(255, 255, 255)} // Blanco }; string resultado = "═══ COLORIZACIÓN DE ELEMENTOS ═══\n"; foreach(var kvp in esquemaColor) { var categoria = kvp.Key; var color = kvp.Value; var collector = new FilteredElementCollector(doc, activeView.Id) .OfCategory(categoria) .WhereElementIsNotElementType(); var overrideSettings = new OverrideGraphicSettings(); overrideSettings.SetProjectionLineColor(color); overrideSettings.SetSurfaceForegroundPatternColor(color); int elementosColoreados = 0; foreach(Element elem in collector) { activeView.SetElementOverrides(elem.Id, overrideSettings); elementosColoreados++; } string nombreCategoria = Category.GetCategory(doc, categoria) != null ? Category.GetCategory(doc, categoria).Name : categoria.ToString(); resultado += "✓ " + nombreCategoria + ": " + elementosColoreados + " elementos " + "RGB(" + color.Red + "," + color.Green + "," + color.Blue + ")\n"; } return resultado + "\n✅ Colorización aplicada en " + activeView.Name; } catch (Exception ex) { return "❌ Error: " + ex.Message; } ``` --- ### CÓDIGO 8.4: RESETEAR VISTA (UNHIDE ALL + RESET OVERRIDES) ¿CUÁNDO USARLO? Para restaurar la vista a su estado original. CÓDIGO COMPLETO: ```csharp try { var doc = document; var uidoc = new UIDocument(doc); var activeView = uidoc.ActiveView; // Mostrar todos los elementos ocultos activeView.DisableTemporaryViewMode(TemporaryViewMode.TemporaryHideIsolate); // Resetear overrides gráficos var collector = new FilteredElementCollector(doc, activeView.Id) .WhereElementIsNotElementType(); int elementosResetados = 0; foreach(Element elem in collector) { activeView.SetElementOverrides(elem.Id, new OverrideGraphicSettings()); elementosResetados++; } return "✅ Vista reseteada\n" + "Todos los elementos visibles\n" + elementosResetados + " overrides eliminados"; } catch (Exception ex) { return "❌ Error: " + ex.Message; } ``` --- ## 📑 2.9 GESTIÓN DE FASES ### CÓDIGO 9.1: LISTAR TODAS LAS FASES DEL PROYECTO CÓDIGO COMPLETO: ```csharp try { var doc = document; var fases = new FilteredElementCollector(doc) .OfClass(typeof(Phase)) .Cast<Phase>() .OrderBy(p => p.get_Parameter(BuiltInParameter.PHASE_SEQUENCE_NUMBER).AsInteger()); string resultado = "═══ FASES DEL PROYECTO ═══\n\n"; resultado += String.Format("{0,-5} {1,-25} {2,-10}\n", "#", "Nombre", "ID"); resultado += new string('─', 42) + "\n"; foreach(Phase fase in fases) { int secuencia = fase.get_Parameter(BuiltInParameter.PHASE_SEQUENCE_NUMBER).AsInteger(); resultado += String.Format("{0,-5} {1,-25} {2,-10}\n", secuencia, fase.Name, fase.Id.IntegerValue); } return resultado; } catch (Exception ex) { return "❌ Error: " + ex.Message; } ``` --- ## 📐 2.10 SECTION BOXES Y VISTAS 3D ### CÓDIGO 10.2: CREAR SECTION BOX PERSONALIZADO ¿CUÁNDO USARLO? Para enfocar una región específica del modelo en 3D. CÓDIGO COMPLETO: ```csharp try { var doc = document; var uidoc = new UIDocument(doc); var activeView = uidoc.ActiveView; if(!(activeView is View3D view3D)) return "❌ La vista activa no es una vista 3D"; // CONFIGURACIÓN: Coordenadas del cubo (metros) double xMin = 0; double xMax = 10; double yMin = 0; double yMax = 10; double zMin = -3; double zMax = 12; BoundingBoxXYZ bbox = new BoundingBoxXYZ(); bbox.Min = new XYZ(xMin 3.28084, yMin 3.28084, zMin 3.28084); bbox.Max = new XYZ(xMax 3.28084, yMax 3.28084, zMax 3.28084); view3D.IsSectionBoxActive = true; view3D.SetSectionBox(bbox); return "✅ Section Box configurado:\n" + "X: " + xMin + "m a " + xMax + "m\n" + "Y: " + yMin + "m a " + yMax + "m\n" + "Z: " + zMin + "m a " + zMax + "m"; } catch (Exception ex) { return "❌ Error: " + ex.Message; } ``` --- ## 🏷️ 2.13 ETIQUETADO Y ANOTACIONES ### CÓDIGO 13.1: ETIQUETAR TODOS LOS MUROS EN VISTA ACTIVA CÓDIGO COMPLETO: ```csharp try { var doc = document; var uidoc = new UIDocument(doc); var activeView = uidoc.ActiveView; bool usarLider = false; var collector = new FilteredElementCollector(doc, activeView.Id) .OfCategory(BuiltInCategory.OST_Walls) .WhereElementIsNotElementType(); string resultado = "═══ ETIQUETAS CREADAS ═══\n"; int etiquetasCreadas = 0; foreach(Element elem in collector) { LocationCurve locCurve = elem.Location as LocationCurve; if(locCurve != null) { Curve curve = locCurve.Curve; XYZ puntoMedio = curve.Evaluate(0.5, true); Reference reference = new Reference(elem); IndependentTag.Create( doc, activeView.Id, reference, usarLider, TagMode.TM_ADDBY_CATEGORY, TagOrientation.Horizontal, puntoMedio ); etiquetasCreadas++; } } return resultado + "\n✅ " + etiquetasCreadas + " etiquetas de muro creadas"; } catch (Exception ex) { return "❌ Error: " + ex.Message; } ``` --- ## 📊 2.14 SCHEDULES Y TABLAS ### CÓDIGO 14.1: CREAR SCHEDULE DE MUROS CÓDIGO COMPLETO: ```csharp try { var doc = document; string nombreSchedule = "Cuadro de Muros"; ElementId categoriaId = new ElementId(BuiltInCategory.OST_Walls); ViewSchedule schedule = ViewSchedule.CreateSchedule(doc, categoriaId); schedule.Name = nombreSchedule; var definition = schedule.Definition; var fieldType = definition.AddField(ScheduleFieldType.Instance, new ElementId(BuiltInParameter.ELEM_TYPE_PARAM)); fieldType.ColumnHeading = "Tipo"; var fieldLevel = definition.AddField(ScheduleFieldType.Instance, new ElementId(BuiltInParameter.WALL_BASE_CONSTRAINT)); fieldLevel.ColumnHeading = "Nivel Base"; var fieldLength = definition.AddField(ScheduleFieldType.Instance, new ElementId(BuiltInParameter.CURVE_ELEM_LENGTH)); fieldLength.ColumnHeading = "Longitud"; var fieldHeight = definition.AddField(ScheduleFieldType.Instance, new ElementId(BuiltInParameter.WALL_USER_HEIGHT_PARAM)); fieldHeight.ColumnHeading = "Altura"; var fieldArea = definition.AddField(ScheduleFieldType.Instance, new ElementId(BuiltInParameter.HOST_AREA_COMPUTED)); fieldArea.ColumnHeading = "Área"; fieldLength.DisplayType = ScheduleFieldDisplayType.Totals; fieldArea.DisplayType = ScheduleFieldDisplayType.Totals; return "✅ Schedule '" + nombreSchedule + "' creado (ID:" + schedule.Id.IntegerValue + ")\n" + "Campos: Tipo, Nivel, Longitud, Altura, Área\n" + "Visible en el navegador de proyecto"; } catch (Exception ex) { return "❌ Error: " + ex.Message; } ``` --- # PARTE 3: DOCUMENTACIÓN ARQUITECTÓNICA ## CÓDIGO: CREAR VISTA DE PLANTA CON VISIBILIDAD CONFIGURADA ¿CUÁNDO USARLO? Para crear vistas de planta arquitectónicas limpias. CÓDIGO COMPLETO: ```csharp try { var doc = document; // CONFIGURACIÓN string nombreNivel = "L4"; string nombreVista = "L4 - ATENEA"; int viewFamilyTypeId = 75905; // Floor Plan estándar // Buscar nivel Level nivelObjetivo = null; var colectorNiveles = new FilteredElementCollector(doc); foreach(Element e in colectorNiveles.OfClass(typeof(Level)).ToElements()) { Level lvl = e as Level; if(lvl != null && lvl.Name == nombreNivel) { nivelObjetivo = lvl; break; } } if(nivelObjetivo == null) return "ERROR: Nivel no encontrado"; // Obtener ViewFamilyType ViewFamilyType tipoVista = null; var colectorTiposVista = new FilteredElementCollector(doc); foreach(Element e in colectorTiposVista.OfClass(typeof(ViewFamilyType)).ToElements()) { ViewFamilyType vft = e as ViewFamilyType; if(vft != null && vft.ViewFamily == ViewFamily.FloorPlan && vft.Id.IntegerValue == viewFamilyTypeId) { tipoVista = vft; break; } } if(tipoVista == null) return "ERROR: ViewFamilyType no encontrado"; // Crear vista ViewPlan nuevaVista = ViewPlan.Create(doc, tipoVista.Id, nivelObjetivo.Id); nuevaVista.Name = nombreVista; nuevaVista.DetailLevel = ViewDetailLevel.Fine; nuevaVista.DisplayStyle = DisplayStyle.HLR; // Categorías a OCULTAR BuiltInCategory[] categoriasOcultar = new BuiltInCategory[] { BuiltInCategory.OST_StructuralColumns, BuiltInCategory.OST_StructuralFraming, BuiltInCategory.OST_StructuralFoundation, BuiltInCategory.OST_DuctCurves, BuiltInCategory.OST_PipeCurves, BuiltInCategory.OST_Conduit, BuiltInCategory.OST_RvtLinks, BuiltInCategory.OST_GenericModel }; int contadorOcultas = 0; foreach(BuiltInCategory categoria in categoriasOcultar) { try { Category cat = Category.GetCategory(doc, categoria); if(cat != null && nuevaVista.CanCategoryBeHidden(cat.Id)) { nuevaVista.SetCategoryHidden(cat.Id, true); contadorOcultas++; } } catch { } } // Categorías a MOSTRAR BuiltInCategory[] categoriasVisibles = new BuiltInCategory[] { BuiltInCategory.OST_Walls, BuiltInCategory.OST_Doors, BuiltInCategory.OST_Windows, BuiltInCategory.OST_Furniture, BuiltInCategory.OST_Stairs, BuiltInCategory.OST_Floors, BuiltInCategory.OST_Grids }; int contadorVisibles = 0; foreach(BuiltInCategory categoria in categoriasVisibles) { try { Category cat = Category.GetCategory(doc, categoria); if(cat != null && nuevaVista.CanCategoryBeHidden(cat.Id)) { nuevaVista.SetCategoryHidden(cat.Id, false); contadorVisibles++; } } catch { } } return "Vista creada: " + nuevaVista.Name + " | ID: " + nuevaVista.Id.IntegerValue + " | Categorías ocultas: " + contadorOcultas + " | Categorías visibles: " + contadorVisibles; } catch (Exception ex) { return "❌ Error: " + ex.Message; } ``` --- # PARTE 4: CÓDIGOS AUXILIARES DE CONSULTA ## BUSCAR IDs DE ZAPATAS ```csharp var collector = new FilteredElementCollector(document) .OfClass(typeof(FamilySymbol)) .OfCategory(BuiltInCategory.OST_StructuralFoundation); string resultado = "Zapatas disponibles:\n"; foreach(Element elem in collector) { var fs = elem as FamilySymbol; if(fs != null) { resultado += "- " + fs.Name + " (ID: " + fs.Id.IntegerValue + ")\n"; } } return resultado; ``` ## BUSCAR IDs DE PILARES ```csharp var collector = new FilteredElementCollector(document) .OfClass(typeof(FamilySymbol)) .OfCategory(BuiltInCategory.OST_StructuralColumns); string resultado = "Pilares disponibles:\n"; foreach(Element elem in collector) { var fs = elem as FamilySymbol; if(fs != null) { resultado += "- " + fs.FamilyName + " : " + fs.Name + " (ID: " + fs.Id.IntegerValue + ")\n"; } } return resultado; ``` ## BUSCAR IDs DE VIGAS ```csharp var collector = new FilteredElementCollector(document) .OfClass(typeof(FamilySymbol)) .OfCategory(BuiltInCategory.OST_StructuralFraming); string resultado = "Vigas disponibles:\n"; foreach(Element elem in collector) { var fs = elem as FamilySymbol; if(fs != null) { resultado += "- " + fs.FamilyName + " : " + fs.Name + " (ID: " + fs.Id.IntegerValue + ")\n"; } } return resultado; ``` --- # PARTE 5: NOTAS TÉCNICAS ## 📐 CONVERSIÓN DE UNIDADES Revit trabaja internamente en PIES. Siempre convertir: | De | A | Fórmula | |----|---|---------| | Metros | Pies | `metros 3.28084` | | Pies | Metros | `pies / 3.28084` | | Milímetros | Pies | `mm / 304.8` | ## ⚙️ SINTAXIS MCP REVIT 1. *Variable del documento:** Usar `document` (minúsculas) 2. Sin interpolación de strings: Usar concatenación tradicional con `+` 3. Sin LINQ avanzado: Usar bucles `foreach` manuales 4. ElementId en Revit 2024+: Usar `new ElementId((long)valor)` ## 🔄 TRANSACCIONES En el entorno MCP de Revit, las transacciones se manejan automáticamente. NO usar: ```csharp // NO USAR EN MCP: using (Transaction t = new Transaction(doc, "...")) { t.Start(); // código t.Commit(); } ``` ## ✅ BUENAS PRÁCTICAS 1. Siempre verificar null antes de usar elementos 2. Activar FamilySymbol antes de crear instancias: `if(!symbol.IsActive) symbol.Activate();` 3. Usar try-catch para manejo de errores 4. Reportar resultados con mensajes claros y emojis --- *Biblioteca compilada por IXA IA - Enero 2026* Basada en Revit API 2024+ y MCP Integration