the first part, getting the "clean" boundingbox is simple. Hide the label and extensionline with the TTT (temporary transaction trick) and determine the boundingbox.
public BoundingBoxXYZ Get_BoundingBox_Clean(Viewport viewport)
{
if (viewport == null) return null;
Document doc = viewport.Document;
string sheetName = viewport.get_Parameter(BuiltInParameter.VIEWPORT_SHEET_NAME).AsString();
List<ViewSheet> _sheets = new FilteredElementCollector(doc)
.OfClass(typeof(ViewSheet))
.Cast<ViewSheet>()
.Where(e => e.Name.Equals(sheetName))
.ToList();
Autodesk.Revit.DB.View sheetview = _sheets.FirstOrDefault();
ElementType porttype = doc.GetElement(viewport.GetTypeId()) as ElementType;
Parameter _showExtensionLine = porttype.get_Parameter(BuiltInParameter.VIEWPORT_ATTR_SHOW_EXTENSION_LINE);
Parameter _labelTag = porttype.get_Parameter(BuiltInParameter.VIEWPORT_ATTR_LABEL_TAG);
BoundingBoxXYZ bb = null;
using (Transaction t = new Transaction(doc, "viewport"))
{
t.Start();
using (SubTransaction st = new SubTransaction(doc))
{
st.Start();
_showExtensionLine.Set((int)0);
_labelTag.Set(ElementId.InvalidElementId);
st.Commit();
}
using (SubTransaction st = new SubTransaction(doc))
{
st.Start();
doc.Regenerate();
bb = viewport.get_BoundingBox(sheetview);
st.Commit();
}
t.RollBack();
}
return bb;
}
the second part requires more acrobatics.
First hide the label, extension line and all annotations. Then make the cropbox as small as possible, and determine the boundingbox.
This is the "zero state" for comparison.
Next make the extension line Visible and again determine the boundingbox. If the box.Min and box.Max have moved, we can calculate the begin and endpoint of the extension line. If not (see picture: box.Min.X == box.Min.X -"zero state") then reposition the cropbox and repeat.

public Line Get_Viewport_Extension_Line(Viewport viewport)
{
try
{
if (viewport == null) return null;
Document doc = viewport.Document;
string sheetName = viewport.get_Parameter(BuiltInParameter.VIEWPORT_SHEET_NAME).AsString();
List<ViewSheet> _sheets = new FilteredElementCollector(doc)
.OfClass(typeof(ViewSheet))
.Cast<ViewSheet>()
.Where(e => e.Name.Equals(sheetName))
.ToList();
Autodesk.Revit.DB.View sheetview = _sheets.FirstOrDefault();
Autodesk.Revit.DB.View view = doc.GetElement(viewport.ViewId) as Autodesk.Revit.DB.View;
ElementType porttype = doc.GetElement(viewport.GetTypeId()) as ElementType;
Parameter _showExtensionLine = porttype.get_Parameter(BuiltInParameter.VIEWPORT_ATTR_SHOW_EXTENSION_LINE);
Parameter _labelTag = porttype.get_Parameter(BuiltInParameter.VIEWPORT_ATTR_LABEL_TAG);
BoundingBoxXYZ crop = view.CropBox;
BoundingBoxXYZ newcrop = view.CropBox;
BoundingBoxXYZ bb = null;
XYZ pt1 = XYZ.Zero; XYZ pt2 = XYZ.Zero;
using (TransactionGroup tg = new TransactionGroup(doc, "get_extensionline"))
{
tg.Start();
using (Transaction t = new Transaction(doc, "crop_Min_clean"))
{
t.Start();
using (SubTransaction st = new SubTransaction(doc))
{
st.Start();
view.get_Parameter(BuiltInParameter.VIEWER_VOLUME_OF_INTEREST_CROP).Set(ElementId.InvalidElementId);
_showExtensionLine.Set((int)0);
_labelTag.Set(ElementId.InvalidElementId);
view.AreAnnotationCategoriesHidden = true;
porttype.get_Parameter(BuiltInParameter.VIEWPORT_ATTR_SHOW_BOX).Set((int)1);
porttype.get_Parameter(BuiltInParameter.VIEWPORT_ATTR_SHOW_LABEL).Set((int)1);
newcrop.Min = new XYZ(crop.Max.X - 0.02, crop.Max.Y - 0.02, crop.Min.Z);
newcrop.Max = new XYZ(crop.Max.X, crop.Max.Y, crop.Max.Z);
view.CropBox = newcrop;
view.CropBoxActive = true;
st.Commit();
}
doc.Regenerate();
t.Commit();
}
bb = viewport.get_BoundingBox(sheetview);
BoundingBoxXYZ testcrop = view.CropBox;
using (Transaction t = new Transaction(doc, "crop_Max"))
{
t.Start();
doc.Regenerate();
_showExtensionLine.Set((int)1);
t.Commit();
}
BoundingBoxXYZ bb2 = viewport.get_BoundingBox(sheetview);
bool MoveRight = bb.Min.X.CompareTo(bb2.Min.X) == 0;
bool moveLeft = bb.Max.X.CompareTo(bb2.Max.X) == 0;
bool moveUp = bb.Min.Y.CompareTo(bb2.Min.Y) == 0;
bool moveDown = bb.Max.Y.CompareTo(bb2.Max.Y) == 0;
pt1 = new XYZ(bb2.Min.X, moveDown? bb2.Min.Y: bb2.Max.Y, bb.Min.Z);
pt2 = new XYZ(bb2.Max.X, pt1.Y, bb.Min.Z);
if ( MoveRight || moveLeft || (moveUp && moveDown))
{
using (Transaction t = new Transaction(doc, "crop_Max"))
{
t.Start();
doc.Regenerate();
double MoveX = MoveRight ? 100 * view.Scale : -100 * view.Scale;
double MoveY = moveUp ? 100 * view.Scale : -100 * view.Scale;
newcrop.Min = new XYZ(newcrop.Min.X + MoveX, newcrop.Min.Y+ MoveY, crop.Min.Z);
newcrop.Max = new XYZ(newcrop.Max.X + MoveX, newcrop.Max.Y +MoveY, crop.Max.Z);
view.CropBox = newcrop;
t.Commit();
}
BoundingBoxXYZ bb3 = viewport.get_BoundingBox(sheetview);
if (MoveRight) { pt1 = new XYZ(bb3.Min.X, pt1.Y, pt1.Z); }
else { pt2 = new XYZ(bb3.Max.X, pt2.Y, pt2.Z); }
double newY = bb3.Max.Y;
if (!moveUp && !moveDown) newY = pt1.Y;
if (moveUp) { newY = bb3.Min.Y; }
pt1 = new XYZ(pt1.X, newY, pt1.Z);
pt2 = new XYZ(pt2.X, newY, pt2.Z);
}
tg.RollBack();
}
return pt1.IsAlmostEqualTo(pt2)? null : Line.CreateBound(pt1,pt2);
}
catch (Exception ex)
{
TaskDialog.Show("catch", ex.ToString());
return null;
}
}