//This method is to be used with the above constructor. It is private because it is not needed outside of this tool's use private static void PlaceSymbolsInView(UIApplication uiApp, string groupingParameter, string subgroupingParameter, Autodesk.Revit.DB.View placementView) { try { RVTDocument doc = uiApp.ActiveUIDocument.Document; //Start a transaction Transaction t = new Transaction(doc, "LoadMaterialSymbolsFamily"); t.Start(); //Get the family loaded into the project by its name, then close the family document in the background Family refFamily = RVTGetElementsByCollection.FamilyByFamilyName(uiApp, Path.GetFileNameWithoutExtension(Properties.Settings.Default.RevitFamilyMaterialsCMSSymbIdMaterialSchedule)); //Add each family symbol (type) to a list of symbols and a dictionary of grouping values indexed by symbol Dictionary <Element, string> familyTypesDict = new Dictionary <Element, string>(); List <Element> familyTypesList = new List <Element>(); foreach (ElementId symbId in refFamily.GetFamilySymbolIds()) { FamilySymbol familySymbol = doc.GetElement(symbId) as FamilySymbol; string paramValue = familySymbol.GetParameters(groupingParameter).First().AsString(); familyTypesList.Add(familySymbol); familyTypesDict.Add(familySymbol, paramValue); } //Next, use Linq to group the family types by ID Use, then sort each group by Mark var familyTypesGroupedQuery = from elemSymbol in familyTypesList orderby elemSymbol.GetParameters(subgroupingParameter).First().AsString() ascending group elemSymbol by elemSymbol.GetParameters(groupingParameter).First().AsString() into mainGroup orderby mainGroup.First().GetParameters(groupingParameter).First().AsString() descending select mainGroup; //The spacing is the distance between each symbol when it is placed in fractional feet. 0.08333 is about 1" which works well for the scale used in making the drafting view double spacing = 0.08333; int rowNum = 0; //Cycle through each group ID Use grouping foreach (var mainGroup in familyTypesGroupedQuery) { int columnNum = 0; //Then for each family symbol in the ID Use grouping, place them in the view, incrementing the X distance by (spacing x the column number) each time. They will be in order of their Mark value foreach (FamilySymbol symbol in mainGroup) { doc.Create.NewFamilyInstance(new XYZ(Convert.ToDouble(columnNum) * spacing, Convert.ToDouble(rowNum) * spacing, 0), symbol, placementView); columnNum++; } rowNum++; } t.Commit(); } catch (Exception e) { MessageBox.Show(e.ToString()); } }
public FloorsCFBRRequest(UIApplication uiApp, String text) { MainUI uiForm = BARevitTools.Application.thisApp.newMainUi; UIDocument uidoc = uiApp.ActiveUIDocument; FloorType selectedFloorType = null; //Get the name of the floor type selected in the MainUI string selectedFloorTypeName = uiForm.floorsCFBRSelectFloorTypeComboBox.Text.ToString(); //Create lists to use locally from the rooms selected from the MainUI, the collection of floor types, and to store newly created floors. List <Room> roomElements = uiForm.floorsCFBRRoomsList; List <FloorType> floorTypes = RVTGetElementsByCollection.DocumentFloorTypes(uiApp); List <Floor> newFloors = new List <Floor>(); //First, make sure the user is running the tool from a plan view if (uidoc.ActiveView.GetType().ToString() != "Autodesk.Revit.DB.ViewPlan") { MessageBox.Show("Please run from a plan view"); } else { //If they are int a plan view, start a transaction Transaction t1 = new Transaction(uidoc.Document, "CreateFloorsByRoom"); t1.Start(); //Cycle through the floor types in the project until the one with a name matching the one selected in the MainUI is found foreach (FloorType floorType in floorTypes) { if (floorType.Name.ToString() == selectedFloorTypeName) { selectedFloorType = floorType; break; } else { continue; } } try { //Generate new GeometryOptions to allow evaluation of room volumes that may not be visible. Options geomOptions = new Options(); geomOptions.IncludeNonVisibleObjects = true; //For each room that was selected with the MainUI... foreach (Room room in roomElements) { //Create a new iterable list for the CurveLoops reprsenting the edges of the room boundary IList <CurveLoop> faceCurveLoops = null; //Get the level associated with the room for floor creation Level roomLevel = room.Level; //Get the geometry of the room GeometryElement roomGeomElements = room.get_Geometry(geomOptions); Solid roomSolid = null; //Cycle through the geometry associated with the room until the solid form is found foreach (GeometryObject geom in roomGeomElements) { if (geom.GetType().ToString() == "Autodesk.Revit.DB.Solid") { roomSolid = geom as Solid; break; } } //If the solid form of the room was found, continue if (roomSolid != null) { //Get the faces of the solid FaceArray solidFaces = roomSolid.Faces; foreach (PlanarFace solidFace in solidFaces) { //Check the direction of the face normal XYZ faceNormal = solidFace.FaceNormal; //If the face normal faced down, it is a bottom face. Because the room cannot be split into multiple portions, //and a split level room is unlikely, it is safe to select the first downward face. if (faceNormal.Z == -1) { //Get the edges of the face as curve loops faceCurveLoops = solidFace.GetEdgesAsCurveLoops(); break; } } } //If the face's curve loops were retrieved, continue if (faceCurveLoops.Count != 0) { try { //Make a new CurveArray from the loops CurveArray curveArray = new CurveArray(); foreach (CurveLoop cloop in faceCurveLoops) { CurveLoopIterator cLoopIter = cloop.GetCurveLoopIterator(); while (cLoopIter.MoveNext()) { curveArray.Append(cLoopIter.Current); } } //The new floow will require the CurveArray, FloorType, Level, and boolean for making it structural (false for this tool's purpose) Floor newFloor = uidoc.Document.Create.NewFloor(curveArray, selectedFloorType, roomLevel, false); //After making the floor, add it to the list of new floors created newFloors.Add(newFloor); } catch { //If the room had more than one edge loop, such as another room was enveloped by the selected room, the operation will fail because the API only allows one loop MessageBox.Show(string.Format("Floor could not be made for {0}, which is likely due to the room having more than one boundary loop. The Revit API only allows for one contiuous loop.", room.Number.ToString())); } } } t1.Commit(); //Provide some feedback to the MainUI uiForm.floorsCFBRDoneLabel.Visible = true; uiForm.floorsCFBRRoomsList = new List <Room>(); } catch { t1.RollBack(); } //If the user wanted to offset the floors by their thickness, this will offset the newly made and collected floors if (uiForm.floorsCFBROffsetFinishFloorCheckBox.Checked) { Transaction t2 = new Transaction(uidoc.Document, "ElevateFloors"); t2.Start(); try { //Cycle through the list of new floors foreach (Floor floor in newFloors) { //Make a new set of geometry options Options geomOptions = new Options(); geomOptions.IncludeNonVisibleObjects = true; //Get the floor geometry and the bounding box of the geometry GeometryElement floorGeometry = floor.get_Geometry(geomOptions); BoundingBoxXYZ floorBBox = floorGeometry.GetBoundingBox(); //Use the minimum and maximum Z coordinates from the bounding box to determine the floor thickness because that's not natively supported in the Revit API double bBoxMinZ = floorBBox.Min.Z; double bBoxMaxZ = floorBBox.Max.Z; double floorThickness = bBoxMaxZ - bBoxMinZ; //Move the floor up with a translation in the Z axis by the thickness value XYZ translation = new XYZ(0, 0, floorThickness); ElementTransformUtils.MoveElement(uidoc.Document, floor.Id, translation); } t2.Commit(); } catch { t2.RollBack(); } } } }
public MaterialsAMLRequest(UIApplication uiApp, String text) { DataGridView dgv = BARevitTools.Application.thisApp.newMainUi.materialsAMLDataGridView; RVTDocument doc = uiApp.ActiveUIDocument.Document; //Get all of the line styles in the project and assign them to a dictionary indexed by line style name Dictionary <string, Category> lineStyleDict = new Dictionary <string, Category>(); foreach (Category lineStyle in RVTGetElementsByCollection.DocumentLineStyles(uiApp)) { lineStyleDict.Add(lineStyle.Name.Replace("ID ", ""), lineStyle); } //All new line styles will use the solid line pattern, so get that from the project ElementId solidPatternId = LinePatternElement.GetSolidPatternId(); //Start the transaction to create the line styles Transaction t1 = new Transaction(doc, "CreateLineStyles"); t1.Start(); //Cycle through the rows of line styles in the MainUI form foreach (DataGridViewRow row in dgv.Rows) { //Get the color of the button in the row and convert it to a Revit color System.Drawing.Color buttonColor = row.Cells["Color"].Style.BackColor; Color revitColor = new Color(buttonColor.R, buttonColor.G, buttonColor.B); //If the Updated column cell is not null, continue if (row.Cells["Updated"].Value != null) { //Assuming the user made a modification to the color for an existing line style and the Mark is part of the dictionary keys... if (row.Cells["Updated"].Value.ToString() == "True" && lineStyleDict.Keys.Contains(row.Cells["Mark"].Value.ToString())) { try { //Get the line style by key name in the dictionary and update its line color to the one from the button Category lineStyleToUpdate = lineStyleDict[row.Cells["Mark"].Value.ToString()]; lineStyleToUpdate.LineColor = revitColor; } catch (Exception e) { MessageBox.Show(e.ToString()); } } } //If the Select column cell is not null, continue if (row.Cells["Select"].Value != null) { //Assuming the user checked the box in the Select column, Mark is not emtpy, and the dictionary of line styles does not already contain a line style with the same mark name... if (row.Cells["Select"].Value.ToString() == "True" && row.Cells["Mark"].Value.ToString() != "" && !lineStyleDict.Keys.Contains(row.Cells["Mark"].Value.ToString())) { try { //Get the category for Lines Category linesCategory = doc.Settings.Categories.get_Item(BuiltInCategory.OST_Lines); //Make a new line style subcategory with the name of the mark value from the Mark column cell, prefixed with ID so it is easier to find during the sort Category newLineStyleCategory = doc.Settings.Categories.NewSubcategory(linesCategory, "ID " + row.Cells["Mark"].Value.ToString()); //Set the line style's color, projection weight, and solid line pattern newLineStyleCategory.LineColor = revitColor; newLineStyleCategory.SetLineWeight(6, GraphicsStyleType.Projection); newLineStyleCategory.SetLinePatternId(solidPatternId, GraphicsStyleType.Projection); //Regenerate the document doc.Regenerate(); } catch (Exception e) { MessageBox.Show(e.ToString()); } } } } t1.Commit(); //Update the DataGridView of the MainUI with the changes and new line styles BARevitTools.Application.thisApp.newMainUi.MaterialsAMLUpdateDGV(dgv); //Make another line style dictionary with the line styles indexed by name (mark) Dictionary <string, Category> newlineStyleDict = new Dictionary <string, Category>(); foreach (Category lineStyle in RVTGetElementsByCollection.DocumentLineStyles(uiApp)) { newlineStyleDict.Add(lineStyle.Name.Replace("ID ", ""), lineStyle); } //Add a default line style to the palette's combo box, then add the checked line styles to a list in alphabetical order SortedList <string, string> materialsToUseList = new SortedList <string, string>(); BARevitTools.Application.thisApp.newMainUi.materialsAMLPalette.paletteMaterialComboBox.Items.Add("Default"); foreach (DataGridViewRow row in dgv.Rows) { if (newlineStyleDict.Keys.Contains(row.Cells["Mark"].Value.ToString()) && row.Cells["Select"].Value.ToString() == "True") { materialsToUseList.Add(row.Cells["Mark"].Value.ToString(), row.Cells["Mark"].Value.ToString()); } } //Assuming there were checked linestyles to add to the palette's combo box, add them to the combo box if (materialsToUseList.Count != 0) { foreach (string item in materialsToUseList.Keys) { BARevitTools.Application.thisApp.newMainUi.materialsAMLPalette.paletteMaterialComboBox.Items.Add(item); } } else { //If there were no additional line styles to add to the combo box, disable it and set it to Default BARevitTools.Application.thisApp.newMainUi.materialsAMLPalette.paletteMaterialComboBox.Text = "Default"; BARevitTools.Application.thisApp.newMainUi.materialsAMLPalette.paletteMaterialComboBox.Enabled = false; } //Show the palette and continue doing requests for the Accent Material Lines tool from there. BARevitTools.Application.thisApp.newMainUi.materialsAMLPalette.Show(); }
public MaterialsCMSRequest(UIApplication uiApp, String text) { MainUI uiForm = BARevitTools.Application.thisApp.newMainUi; ProgressBar progressBar = uiForm.materialsCMSExcelCreateSymbolsProgressBar; DataGridView dgv = uiForm.materialsCMSExcelDataGridView; int rowsCount = dgv.Rows.Count; int columnsCount = dgv.Columns.Count; List <string> familyTypesMade = new List <string>(); //Prepare the progress bar. The column count is one less because the first column is the column for family type names progressBar.Minimum = 0; progressBar.Maximum = (rowsCount) * (columnsCount - 1); progressBar.Step = 1; progressBar.Visible = true; RVTDocument doc = uiApp.ActiveUIDocument.Document; //Reset the progress bar uiForm.materialsCMSExcelCreateSymbolsProgressBar.Value = 0; //First, try to use the family from the project. If that fails, use the family file Family familyToUse = RVTGetElementsByCollection.FamilyByFamilyName(uiApp, Path.GetFileNameWithoutExtension(Properties.Settings.Default.RevitFamilyMaterialsCMSSymbIdMaterialSchedule)); //Assuming nothing went to hell in the process of loading one famiy... if (familyToUse != null) { //Save out the family to use RVTDocument tempFamDoc = doc.EditFamily(familyToUse); RVTOperations.SaveRevitFile(uiApp, tempFamDoc, @"C:\Temp\" + tempFamDoc.Title, true); //Open the family to use and get its FamilyManager RVTDocument famDoc = RVTOperations.OpenRevitFile(uiApp, @"C:\Temp\" + Path.GetFileName(Properties.Settings.Default.RevitFamilyMaterialsCMSSymbIdMaterialSchedule)); FamilyManager famMan = famDoc.FamilyManager; //Get the parameters from the Family Manager and add them to a dictionary FamilyParameterSet parameters = famMan.Parameters; Dictionary <string, FamilyParameter> famParamDict = new Dictionary <string, FamilyParameter>(); foreach (FamilyParameter param in parameters) { famParamDict.Add(param.Definition.Name, param); } //Start a new transaction to make the new family types in the family to use using (Transaction t1 = new Transaction(famDoc, "MakeNewTypes")) { t1.Start(); //Cycle through the rows in the dgv for (int i = 0; i < rowsCount; i++) { //The first column cell will be the type name string newTypeName = dgv.Rows[i].Cells[0].Value.ToString(); //Get the family type names in the family Dictionary <string, FamilyType> existingTypeNames = RVTOperations.GetFamilyTypeNames(famMan); //If the family to make from the DGV does not exist in the dictionary keys... if (!existingTypeNames.Keys.Contains(newTypeName)) { //Make the family type and add it to the list of types made FamilyType newType = famMan.NewType(newTypeName); famMan.CurrentType = newType; familyTypesMade.Add(newType.Name); } else { //If the type exists, set the current type it from the dictionary and add it to the list of types made famMan.CurrentType = existingTypeNames[newTypeName]; familyTypesMade.Add(famMan.CurrentType.Name); } //Next, evaluate the columns that contain parameters for (int j = 1; j < columnsCount; j++) { //The parameter names will be retrieved from the column HeaderText property string paramName = dgv.Columns[j].HeaderText; //Meanwhile the parameter value will come from the DGV cells var paramValue = dgv.Rows[i].Cells[j].Value; try { //If the parameter dictionary contains the parameter and the value to assign it is not empty, continue. if (paramValue.ToString() != "" && famParamDict.Keys.Contains(paramName)) { //Get the family parameter and check if it is locked by a formula FamilyParameter param = famParamDict[paramName]; if (!param.IsDeterminedByFormula) { //If it is not locked by a formula, set the parameter ParameterType paramType = param.Definition.ParameterType; RVTOperations.SetFamilyParameterValue(famMan, param, paramValue); } } } catch {; } finally { //Always perform the step to indicate the progress. progressBar.PerformStep(); } } } t1.Commit(); } //Use another transaction to delete the types that were not needed using (Transaction t2 = new Transaction(famDoc, "DeleteOldTypes")) { t2.Start(); //Cycle through the family types and determine if it is in the list of types made foreach (FamilyType type in famMan.Types) { if (!familyTypesMade.Contains(type.Name)) { //If the type is not in the list of types made, delete it from the family file famMan.CurrentType = type; famMan.DeleteCurrentType(); } } t2.Commit(); } //Save the family document at this point as all of the types and their parameters have been set famDoc.Close(true); using (Transaction t3 = new Transaction(doc, "LoadFamily")) { t3.Start(); doc.LoadFamily(@"C:\Temp\" + Path.GetFileName(Properties.Settings.Default.RevitFamilyMaterialsCMSSymbIdMaterialSchedule), new RVTFamilyLoadOptions(), out Family loadedFamily); t3.Commit(); } //Get the drafting view type in the project for BA Drafting View, else just get the first drafting view type ViewDrafting placementView = null; var draftingViews = new FilteredElementCollector(doc).OfClass(typeof(ViewDrafting)).WhereElementIsNotElementType().ToElements(); ViewFamilyType draftingViewType = null; try { //From the view family types collection, get the first one where its name is BA Drafting View draftingViewType = new FilteredElementCollector(doc).OfClass(typeof(ViewFamilyType)).WhereElementIsElementType().ToElements().Where(elem => elem.Name == "BA Drafting View").First() as ViewFamilyType; } catch { //Well, crap. It doesn't exist. Just get the first type then and call it good. draftingViewType = new FilteredElementCollector(doc).OfClass(typeof(ViewFamilyType)).WhereElementIsElementType().ToElements().First() as ViewFamilyType; } //Start a transaction for making the ID Material View and placing the family symbol types using (Transaction t4 = new Transaction(doc, "MakeIDMaterialView")) { t4.Start(); foreach (ViewDrafting view in draftingViews) { //Find the view named ID Material View, or whatever jibberish someone typed in the CMS text box for the name to use. in the drafting views if (view.Name == "ID Material View" || view.Name == uiForm.materialsCMSSetViewNameTextBox.Text) { //Delete the drafting view doc.Delete(view.Id); doc.Regenerate(); break; } else { continue; } } //Make a new view placementView = ViewDrafting.Create(doc, draftingViewType.Id); placementView.Scale = 1; if (uiForm.materialsCMSSetViewNameTextBox.Text != "") { //If someone defined a custom view name, use that and strip out brackets if they exist placementView.Name = uiForm.materialsCMSSetViewNameTextBox.Text.Replace("{", "").Replace("}", ""); } else { //Otherwise, this will be the new ID Material View placementView.Name = "ID Material View"; } try { //Set the view sort parameters if they exist placementView.GetParameters(Properties.Settings.Default.BAViewSort1).First().Set("2 Plans"); placementView.GetParameters(Properties.Settings.Default.BAViewSort2).First().Set("230 Finish Plans"); } catch (Exception e) { MessageBox.Show(e.ToString()); } doc.Regenerate(); t4.Commit(); } //Do magic to place each symbol in its view by calling the method below in this class PlaceSymbolsInView(uiApp, "ID Use", "Mark", placementView); //Clean up the files from the operations GeneralOperations.CleanRfaBackups(GeneralOperations.GetAllRvtBackupFamilies(@"C:\Temp\", false)); File.Delete(@"C:\Temp\" + Path.GetFileName(Properties.Settings.Default.RevitFamilyMaterialsCMSSymbIdMaterialSchedule)); Application.thisApp.newMainUi.materialsCMSFamilyToUse = RVTGetElementsByCollection.FamilyByFamilyName(uiApp, Path.GetFileNameWithoutExtension(Properties.Settings.Default.RevitFamilyMaterialsCMSSymbIdMaterialSchedule)); } else { //If the family could not be found, well, let the user know of this. MessageBox.Show(String.Format("The {0} family could not be found in the project.", Path.GetFileNameWithoutExtension(Properties.Settings.Default.RevitFamilyMaterialsCMSSymbIdMaterialSchedule))); } }