Hi, everyone,
I am working on a project in which we want to locate objects with the nearest grids intersection.
so i have used the column location mark property to meet my need. the solution is described with the codes belows:
using (TransactionGroup transGroup = new TransactionGroup(document,"Transaction Group")) { transGroup.Start("Upgrade signages identity informations"); foreach (ElementId eid in SelectedElements) { var e = document.GetElement(eid) as FamilyInstance; LocationPoint lp = e.Location as LocationPoint; XYZ loc = new XYZ(lp.Point.X,lp.Point.Y,0); ElementId levelId = e.LevelId; Level level = document.GetElement(levelId) as Level; Transaction tr1 = new Transaction(document,"Get Coordinates"); tr1.Start(); FamilyInstance newPoteau = document.Create.NewFamilyInstance(loc, familySymbol, level, Autodesk.Revit.DB.Structure.StructuralType.Column); tr1.Commit(); Parameter p1 = newPoteau.get_Parameter(BuiltInParameter.COLUMN_LOCATION_MARK); string locationParam = p1.AsString(); //enlever distance dans la chaine de caractère int index1= locationParam.IndexOf('('); int index2= locationParam.IndexOf(')'); if(index1!=-1) {locationParam = locationParam.Remove(index1,index2-index1+1);} int index3= locationParam.IndexOf('('); if(index3!=-1) {locationParam = locationParam.Remove(index3);} locationParam = locationParam.Replace('-',','); //Take Level Code and Increment number Parameter pLevel = level.get_Parameter(levelCodeParam); levelCode = pLevel.AsString(); if(String.IsNullOrEmpty(levelCode)) { levelCode ="??"; } Parameter pIncrement = e.get_Parameter(incrementParam); increment = pIncrement.AsString(); if(String.IsNullOrEmpty(increment)) { increment="1"; } Parameter pType = document.GetElement(e.GetTypeId()).get_Parameter(signageTypeParam); signageType = pType.AsString(); Parameter pID= e.get_Parameter(BuiltInParameter.DOOR_NUMBER); signageID = signageType+"-"+levelCode+"-"+locationParam+"-"+increment; //Fill Tag Transaction tr2 = new Transaction (document,"Fill Tag"); tr2.Start(); e.get_Parameter(xyParam).Set(locationParam); document.Delete(newPoteau.Id); e.get_Parameter(signageLevelCodeParam).Set(levelCode); e.get_Parameter(incrementParam).Set(increment); e.get_Parameter(BuiltInParameter.DOOR_NUMBER).Set(signageID); tr2.Commit(); } transGroup.Assimilate(); }
I have to commit a column creation transaction in order to get the COLUMN_LOCATION_MARK property, and then delete the column in a other transaction.
I am pretty sure that this is not a good idea to do the thing in this way since there are so many operations on the file. so i am wondering if i can:
1. get the things done without commit the transaction in which we have creation and supression of a column object.
2. if there's a API methode to get the location mark
Thanks a lot.
Dear Fangchao Gong,
Thank you for your query.
I do not understand what you are trying to achieve, nor what the code has to do with your brief description.
Please elaborate.
Thank you.
Best regards,
Jeremy
Hi,Jeremy, Thanks a lot for your reply. And also thanks a lot for your blog, the articles are very helpful and I have learnt a lot from them.
For the macro, i want to know the location of all the objects in the project ( the coordinates like X1, Y1). While we are studying the project, we want to find the object rapidly with the grids intersection.
In REVIT, only the structural column have a property "COLUMN_LOCATION_MARK" which gives me the possiblity to have this kind of coordinates.
This is why i have written the codes above to place a structural column and then commit a transaction,after which I can get a "COLUMN_LOCATION_MARK" value. copy and paste it to one of my object properties. and at last, delete the column object.
I am wondering if there is a better way to do this thing in Revit since there is so many operations on the model.
Dear Fangchao Gong,
Thank you for your update, appreciation, and more detailed explanation.
When you say "coordinates like X1, Y1", I must answer that every single object in Revit provides those straight out of the box, with no need whatsoever for the expensive acrobatics you describe.
I have no idea why you think you need a structural column and its COLUMN_LOCATION_MARK property to access this kind of coordinates.
Well, actually, if I attempt a guess, I would surmise that you might be after the coordinates converted from the local project coordinate system to some kind of global coordinate system.
In that case, there are much simpler and more direct solutions.
Hopefully, this one will fulfil your needs:
Best regards,
Jeremy
Hi, Jeremy,
With a picture, i can explain better my propose. 🙂 Sorry for my English, i haven't praticed it for a long time. ( France here 🙂 )
To locate a object, i can have a X,Y coordinate. but it's too diffcult to find it if we have only a Dwg and Excel file. so we want to locate it with the grid intersection.
for exemple, the red point on the image, i want a value like (A,2).
If the COLUMN_LOCATION_MARK is not the only solution. i have to read all the grids intersections and calculate the distance between my object and all of them to find the smallest value?
Dear Fangchao Gong,
Thank you for your update and helpful sample image.
Your English is perfectly fine 🙂
Now I understand better what you are after.
Yes, I would definitely suggest calculating the grid line intersection points and determining the closest one yourself.
That sounds vastly more efficient than asking Revit to create temporary BIM elements and commit transactions to place and query them.
You could even have additional fun by defining a lexicographical ordering on the grid points and managing them in a .NET dictionary.
That would make the lookup process extremely fast.
Please let me know if you need any help with that.
If so, please provide a complete reproducible case and sample model to play with:
http://thebuildingcoder.typepad.com/blog/about-the-author.html#1b
Thank you!
I hope this helps.
Good luck and best regards,
Jeremy
Hi Chao,
Very funny to see you here 🙂 Comment vas-tu ?
It seems that everybody is now digging in the Revit API !
The subject you want to deal with is very interesting ! Please let us know if you achieve your goals !
M. V.
yes Maxime, it helps a lot the api.
and with the help of Jeremy, i have at last the things done .-)
public void getNearestIntersectionPoint() { UIDocument uidoc =ActiveUIDocument; Document doc = ActiveUIDocument.Document; Selection sel = uidoc.Selection; ICollection<ElementId> ecol = sel.GetElementIds(); Dictionary<string,XYZ> intersectionPoints = getIntersections(doc); string intersection = "??"; foreach(ElementId eid in ecol) { Element e = doc.GetElement(eid); LocationPoint p = e.Location as LocationPoint; XYZ xyz= new XYZ(p.Point.X, p.Point.Y,0); double distanceMin = 0; double distance =0; distanceMin =xyz.DistanceTo( intersectionPoints.First().Value); foreach (KeyValuePair<string,XYZ> kp in intersectionPoints) { distance = xyz.DistanceTo(kp.Value); if (distance<distanceMin) {distanceMin=distance; intersection = kp.Key; } } double distanceInMeter = distanceMin/3.281; MessageBox.Show(intersection); } } #region build dictionary public Dictionary<string,XYZ> getIntersections(Document doc) { string coordinate = null; string coordA= null; string coordB= null; string coordC = null; Dictionary<string,XYZ> intersectionPoints = new Dictionary<string,XYZ>(); ICollection<ElementId> grids = new FilteredElementCollector(doc).WherePasses(new ElementCategoryFilter(BuiltInCategory.OST_Grids)).WhereElementIsNotElementType().ToElementIds(); ICollection<ElementId> refgrid = new FilteredElementCollector(doc).WherePasses(new ElementCategoryFilter(BuiltInCategory.OST_Grids)).WhereElementIsNotElementType().ToElementIds(); foreach( ElementId eid in grids) { Grid g = doc.GetElement(eid) as Grid; coordA = g.Name; Curve c = g.Curve; refgrid.Remove(eid); foreach(ElementId eid2 in refgrid) { Grid g2 = doc.GetElement(eid2) as Grid; coordB = g2.Name; Curve c2 = g2.Curve; IntersectionResultArray results; SetComparisonResult result = c.Intersect(c2, out results); if( result != SetComparisonResult.Overlap ) { } else if( results == null || results.Size != 1 ) {} else if (results.Size>0) { for (int i =0; i<results.Size; i ++) { IntersectionResult iresult = results.get_Item(i); coordC = i.ToString(); coordinate = coordA+","+coordB+"-"+coordC; XYZ point = iresult.XYZPoint; intersectionPoints.Add(coordinate,point); } } continue; } } return intersectionPoints; } #endregion
and Jeremy, Thank you a lot 🙂
I'm very interested in this but I'm not so much in the coding side. I go as far as dynamo.
I do wish this was a property that Revit just automatically filled out as this would translate very nicely to equipment in BIM 360 field and give an object an actual location.
Regardless of my coding knowledge I still look forward to seeing what you come up with. Maybe it could become an add-on?
Thanks,