Hey RPTHOMAS108,
You wrote This below is in VB, can easily be converted to C#.""
Well, I got it translated, line by line, and it does not seem to work, any idea what I am missing?
@RPTHOMAS108 wrote:
The first thing to note is that you are using rac_advanced_sample_project.rvt not the basic project since this is the only project with the named view sheet you mentioned.
I've included some code that plots bounding box position of doors to the sheet coords system. The transform is important even for plan views as although these usually align with the model coord system sometimes they are rotated:
The sheet coord system is from bottom left to top right. I don't know how the system in PDF/XPS is measured but a further translation may be required. It is important to note that the title block can be placed anywhere in the sheet space but when it is printed this space obviously gets truncated to the extents of the title block. Therefore the location of things relative to the title block is more relevant than the absolute sheet coords themselves.
This below is in VB, can easily be converted to C#.
Private Shared Function GetElements(Of T As Element)(Doc As Document, Optional View As View = Nothing) As List(Of T)
Dim FEC As FilteredElementCollector
If View Is Nothing Then
FEC = New FilteredElementCollector(Doc)
Else
FEC = New FilteredElementCollector(Doc, View.Id)
End If
Dim ECF As New ElementClassFilter(GetType(T))
Dim Out As List(Of T) = FEC.WherePasses(ECF).ToElements.Cast(Of T).ToList
Return Out
End Function
Private Shared Function GetElements(Doc As Document, BIC As BuiltInCategory, IsType As Boolean,
Optional View As View = Nothing) As List(Of Element)
Dim FEC As FilteredElementCollector
If View Is Nothing Then
FEC = New FilteredElementCollector(Doc)
Else
FEC = New FilteredElementCollector(Doc, View.Id)
End If
Dim ECF As New ElementCategoryFilter(BIC)
Dim Out As List(Of Element)
If IsType Then
Out = FEC.WherePasses(ECF).WhereElementIsElementType.ToElements
Else
Out = FEC.WherePasses(ECF).WhereElementIsNotElementType.ToElements
End If
Return Out
End Function
Private Function TObj116(ByVal commandData As Autodesk.Revit.UI.ExternalCommandData,
ByRef message As String, ByVal elements As Autodesk.Revit.DB.ElementSet) As Result
If commandData.Application.ActiveUIDocument Is Nothing Then Return Result.Cancelled Else
Dim UIDoc As UIDocument = commandData.Application.ActiveUIDocument
Dim Doc As Document = UIDoc.Document
Dim AcView As ViewSheet = TryCast(Doc.ActiveView, ViewSheet)
If AcView Is Nothing Then Return Result.Cancelled Else
Dim FEC As New FilteredElementCollector(Doc, AcView.Id)
Dim VP_lst As List(Of Viewport) = GetElements(Of Viewport)(Doc, AcView)
Dim TB_Lst As List(Of Element) = GetElements(Doc, BuiltInCategory.OST_TitleBlocks, False, AcView)
If TB_Lst.Count <> 1 Then
'We need this to be the only one in the view
'We need to find the minimum bounding box point as that is most important for the printed sheet
Return Result.Cancelled
End If
'We use these points only to relate the sheet coord system to the printed lines (offset from corner of title block)
'i.e. title block can be located anywhere in sheet coord space but when it is printed
'such a coord space will be truncated to the extents of the title block
Dim TB_Pt_min = TB_Lst(0).BoundingBox(AcView).Min
Dim TB_Pt_max = TB_Lst(0).BoundingBox(AcView).Max
TB_Pt_min = New XYZ(TB_Pt_min.X, TB_Pt_min.Y, 0) 'Zero Z
TB_Pt_max = New XYZ(TB_Pt_max.X, TB_Pt_max.Y, 0) 'Zero Z
Dim TB_TopLeft = New XYZ(TB_Pt_min.X, TB_Pt_max.Y, 0)
Using Tx As New Transaction(Doc, "Door points on sheet")
If Tx.Start = TransactionStatus.Started Then
For VPi = 0 To VP_lst.Count - 1
Dim VPrt As Viewport = VP_lst(VPi)
Dim V As View = Doc.GetElement(VPrt.ViewId)
Dim Doors As List(Of Element) = GetElements(Doc, BuiltInCategory.OST_Doors, False, V)
Dim VPoln As Outline = VPrt.GetBoxOutline 'Viewport outline in Sheet coords
Dim Voln As BoundingBoxUV = V.Outline 'View outline
Dim Scale As Integer = V.Scale
'Transform for view coords (very important for rotated view plans set to true north etc.)
'completely not important when view plan is not rotated
Dim T As Transform = Transform.Identity
T.BasisX = V.RightDirection
T.BasisY = V.UpDirection
T.BasisZ = V.ViewDirection
T.Origin = V.Origin
'You can probably get this transform above from elsewhere such as cropbox.
Dim Voln_cen = (Voln.Min + Voln.Max) / 2 'View outline centre
Dim VPcen As XYZ = (VPoln.MaximumPoint + VPoln.MinimumPoint) / 2 'Viewport centre
VPcen = New XYZ(VPcen.X, VPcen.Y, 0) 'Zero z
'Correction offset from VCen to centre of Viewport in sheet coords
Dim Offset As XYZ = VPcen - New XYZ(Voln_cen.U, Voln_cen.V, 0)
For DRi = 0 To Doors.Count - 1
Dim Dr As Element = Doors(DRi)
Dim BB As BoundingBoxXYZ = Dr.BoundingBox(V)
'Location of door bounding box in sheet coords
Dim J1 As XYZ = T.Inverse.OfPoint(BB.Min).Multiply(1 / Scale) + Offset
Dim J2 As XYZ = T.Inverse.OfPoint(BB.Max).Multiply(1 / Scale) + Offset
'These points are plotted in the sheet coord space
'This may not relate to pdf space i.e. location of title block is important
J1.DrawPoint2D(Doc, 0.01) 'EXTENSION METHOD
J2.DrawPoint2D(Doc, 0.01) 'EXTENSION METHOD
'TODO Convert to PDF/XPS graphics space system.
'Use TB_pt_min & TB_pt_max & TB_TopLeft
'I am unsure of the coord system of XPS/PDF (graphics are sometimes plotted downwards from top left point
'not up from bottom right as considered above in the sheet coord system
'therefore need to transform into that space if applicable
'e.g. Y = ScreenHeight - OffsetFromBottom
Next
Next
Tx.Commit()
End If
End Using
End Function
using System;
using System.Collections.Generic;
using System.Linq;
using Autodesk.Revit.UI;
using Autodesk.Revit.DB;
namespace HelloRevit
{
[Autodesk.Revit.Attributes.Transaction(Autodesk.Revit.Attributes.TransactionMode.Manual)]
class Class1 : IExternalCommand
{
public Result Execute(ExternalCommandData revit, ref string message, ElementSet elements)
{
TaskDialog.Show("Revit", "Hello World C#");
TObj116(revit, ref message, elements);
TaskDialog.Show("Revit", "C# Done script");
return Result.Succeeded;
}
private static List<T> GetElements<T>(Document doc, View view = null) where T : Element
{
FilteredElementCollector fec;
if (view == null)
fec = new FilteredElementCollector(doc);
else
fec = new FilteredElementCollector(doc, view.Id);
ElementClassFilter ecf = new ElementClassFilter(typeof(T));
List<T> outR = fec.WherePasses(ecf).ToElements().Cast<T>().ToList();
return outR;
}
private static List<Element> GetElements(Document doc, BuiltInCategory bic, bool isType, View view = null)
{
FilteredElementCollector fec;
if (view == null)
fec = new FilteredElementCollector(doc);
else
fec = new FilteredElementCollector(doc, view.Id);
ElementCategoryFilter ecf = new ElementCategoryFilter(bic);
List<Element> outR;
if (isType)
outR = fec.WherePasses(ecf).WhereElementIsElementType().ToElements().ToList();
else
outR = fec.WherePasses(ecf).WhereElementIsNotElementType().ToElements().ToList();
return outR;
}
private Result TObj116(ExternalCommandData commandData, ref string message, ElementSet elements)
{
if (commandData.Application.ActiveUIDocument == null)
return Result.Cancelled;
UIDocument uiDocument = commandData.Application.ActiveUIDocument;
Document doc = uiDocument.Document;
ViewSheet acView = doc.ActiveView as ViewSheet;
if (acView == null)
return Result.Cancelled;
FilteredElementCollector fec = new FilteredElementCollector(doc, acView.Id);
List<Viewport> vp_lst = GetElements<Viewport>(doc, acView);
List<Element> tb_lst = GetElements(doc, BuiltInCategory.OST_TitleBlocks, false, acView);
if (tb_lst.Count != 1)
// We need this to be the only one in the view
// We need to find the minimum bounding box point as that is most important for the printed sheet
return Result.Cancelled;
/* We use these points only to relate the sheet coord system to the printed lines (offset from corner of title block)
* i.e. title block can be located anywhere in sheet coord space but when it is printed
* such a coord space will be truncated to the extents of the title block */
var tb_pt_min = tb_lst[0].get_BoundingBox(acView).Min;
var tb_pt_max = tb_lst[0].get_BoundingBox(acView).Max;
tb_pt_min = new XYZ(tb_pt_min.X, tb_pt_min.Y, 0); // Zero Z
tb_pt_max = new XYZ(tb_pt_max.X, tb_pt_max.Y, 0); // Zero Z
var tb_TopLeft = new XYZ(tb_pt_min.X, tb_pt_max.Y, 0);
using (Transaction tx = new Transaction(doc, "Door points on sheet"))
{
if (tx.Start() == TransactionStatus.Started)
{
for (int vpi = 0; vpi <= vp_lst.Count - 1; vpi++)
{
Viewport vprt = vp_lst[vpi];
View v = (View)doc.GetElement(vprt.ViewId);
List<Element> doors = GetElements(doc, BuiltInCategory.OST_Doors, false, v);
Outline vpoln = vprt.GetBoxOutline(); // Viewport outline in Sheet coords.
BoundingBoxUV voln = v.Outline; // View outline.
int scale = v.Scale;
/*Transform for view coords (very important for rotated view plans set to true north etc.)
completely not important when view plan is not rotated*/
Transform t = Transform.Identity;
t.BasisX = v.RightDirection;
t.BasisY = v.UpDirection;
t.BasisZ = v.ViewDirection;
t.Origin = v.Origin;
// You can probably get this transform above from elsewhere such as cropbox.
var voln_cen = (voln.Min + voln.Max) / 2; // View outline centre
XYZ vpcen = (vpoln.MaximumPoint + vpoln.MinimumPoint) / 2; // Viewport centre
vpcen = new XYZ(vpcen.X, vpcen.Y, 0); // Zero z
// Correction offset from VCen to centre of Viewport in sheet coords
XYZ offset = vpcen - new XYZ(voln_cen.U, voln_cen.V, 0);
for (int dri = 0; dri <= doors.Count - 1; dri++)
{
Element dr = doors[dri];
BoundingBoxXYZ bb = dr.get_BoundingBox(v);
// Location of door bounding box in sheet coords
XYZ j1 = t.Inverse.OfPoint(bb.Min).Multiply(1 / scale) + offset;
XYZ j2 = t.Inverse.OfPoint(bb.Max).Multiply(1 / scale) + offset;
// These points are plotted in the sheet coord space
// This may not relate to pdf space i.e. location of title block is important
// J1.DrawPoint2D(Doc, 0.01) 'EXTENSION METHOD
// J2.DrawPoint2D(Doc, 0.01) 'EXTENSION METHOD
j1 = new XYZ(j1.X, j1.Y, 0); // Zero Z
j2 = new XYZ(j2.X, j2.Y, 0); // Zero Z
// Create line 0.01 ft either side of point in Basis.X and Basis.Y directions
Line ln0 = Line.CreateBound(j1 - (XYZ.BasisX * 0.01), j1 + (XYZ.BasisX * 0.01));
Line ln1 = Line.CreateBound(j1 - (XYZ.BasisY * 0.01), j1 + (XYZ.BasisY * 0.01));
Line ln2 = Line.CreateBound(j2 - (XYZ.BasisX * 0.01), j2 + (XYZ.BasisX * 0.01));
Line ln3 = Line.CreateBound(j2 - (XYZ.BasisY * 0.01), j2 + (XYZ.BasisY * 0.01));
doc.Create.NewDetailCurve(acView, ln0);
doc.Create.NewDetailCurve(acView, ln1);
doc.Create.NewDetailCurve(acView, ln2);
doc.Create.NewDetailCurve(acView, ln3);
/*Dim gs As GraphicsStyle ' = Autodesk.Revit.DB.Arc.LineStyle As GraphicsStyle
gs.GraphicsStyleCategory.LineColor = New Color(250, 10, 10)
Autodesk.Revit.DB.CurveByPointsUtils.CreateRectangle(Doc, J1, J2)
TODO Convert to PDF/XPS graphics space system.
Use TB_pt_min & TB_pt_max & TB_TopLeft
I am unsure of the coord system of XPS/PDF (graphics are sometimes plotted downwards from top left point
not up from bottom right as considered above in the sheet coord system
therefore need to transform into that space if applicable
e.g. Y = ScreenHeight - OffsetFromBottom*/
}
}
tx.Commit();
}
}
return Result.Succeeded;
}
}
}