Files
SzmediTools/Szmedi.RvKits/Drawing/DimensionView3dCmd.cs
2025-09-16 16:06:41 +08:00

727 lines
30 KiB
C#
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
using Autodesk.Revit.Attributes;
using Autodesk.Revit.DB;
using Autodesk.Revit.UI;
using Nice3point.Revit.Toolkit.External;
using System;
using System.Globalization;
using System.Linq;
using System.Reflection;
using System.Windows;
using System.Windows.Media;
namespace Szmedi.RvKits.DrawingTools
{
[Transaction(TransactionMode.Manual)]
public class DimensionView3dCmd : ExternalCommand
{
public override void Execute()
{
ViewFamilyType viewFamilyType = new FilteredElementCollector(Document)
.OfClass(typeof(ViewFamilyType))
.Cast<ViewFamilyType>()
.FirstOrDefault(t => t.ViewFamily == ViewFamily.ThreeDimensional);
IEnumerable<Grid> grids = new FilteredElementCollector(Document).OfClass(typeof(Grid)).Cast<Grid>();
View3D myView = null;
int n = 100;
if (!grids.Any())
{
Result = Result.Cancelled;
return;
}
Document.Invoke(
_ =>
{
if (viewFamilyType != null)
{
myView = View3D.CreateIsometric(Document, viewFamilyType.Id);
}
for (int i = 0; i < n; i++)
{
try
{
myView.Name = $"三维轴测视图_{i}";
break;
}
catch (Autodesk.Revit.Exceptions.ArgumentException) { }
}
myView.SaveOrientationAndLock();
List<ModelCurve> mcurves = Create3dGrid(myView, grids);
Document.Regenerate();
CreateDimension(Document, myView, mcurves);
},
"三维标注"
);
UiDocument.ActiveView = myView;
}
/// <summary>
/// 获取族实例所有面(实际为族类型的所有面)
/// </summary>
/// <param name="instance"></param>
/// <param name="options"></param>
/// <returns></returns>
public static List<Face> GetFacesByFamilyInstance(FamilyInstance instance, Options options)
{
List<Face> faces = new();
//根据打开的方式得到几何信息
GeometryElement geometry = instance.get_Geometry(options);
foreach (GeometryObject geomObj in geometry)
{
//geomObj为几何实例
GeometryInstance geomInstance = geomObj as GeometryInstance;
if (geomInstance == null)
{
continue;
}
//族实例未修改过(连接,剪切,复制,扩展)
bool usesSymbolGeometry = instance is not null && !instance.HasModifiedGeometry();
bool bo = instance.HasModifiedGeometry();
GeometryElement instanceGeometry = usesSymbolGeometry
? geomInstance.GetSymbolGeometry()
: geomInstance.GetInstanceGeometry();
if (instanceGeometry != null)
{
//instanceGeometry.GetTransformed();
//从实例中找到实例的几何体
foreach (GeometryObject instObj in instanceGeometry)
{
//三维的实体
Solid instSolid = instObj as Solid;
if (instSolid == null || instSolid.Faces.Size == 0 || instSolid.Edges.Size == 0)
{
continue;
}
foreach (Face face in instSolid.Faces)
{
faces.Add(face);
}
}
}
//geomObj为几何体
Solid solid = geomObj as Solid;
if (solid != null)
{
if (solid.Faces.Size == 0 || solid.Edges.Size == 0)
{
continue;
}
foreach (Face face in solid.Faces)
{
faces.Add(face);
}
}
}
return faces;
}
/// <summary>
/// 获取元素侧面
/// </summary>
/// <param name="elem"></param>
/// <returns></returns>
public static List<Face> GetSideFacesByElement(Element elem)
{
Options opt = new() { ComputeReferences = true, DetailLevel = ViewDetailLevel.Fine };
GeometryElement ge = elem.get_Geometry(opt);
List<Face> lstpf = new();
foreach (GeometryObject obj in ge)
{
Solid solid = obj as Solid;
if (solid != null)
{
foreach (Face face in solid.Faces)
{
PlanarFace pf = face as PlanarFace;
if (pf != null)
{
//点乘即面的法向与Z轴始终垂直
double dotp = pf.FaceNormal.DotProduct(XYZ.BasisZ);
if (dotp is < 1.0e-09 and > (-1.0e-09)) //近似为0
{
lstpf.Add(pf);
}
//if (pf.FaceNormal.CrossProduct(wall.Orientation).IsZeroLength())
//{
// lstpf.Add(pf);
//}
}
CylindricalFace cy = face as CylindricalFace;
if (cy != null)
{
lstpf.Add(cy);
}
}
return lstpf;
}
}
return lstpf;
}
private List<ModelCurve> Create3dGrid(View view, IEnumerable<Grid> grids)
{
Document Document = view.Document;
List<TextNoteType> textnotetypes = new FilteredElementCollector(Document)
.OfClass(typeof(TextNoteType))
.Cast<TextNoteType>()
.ToList();
TextNoteType textnotetype = textnotetypes.FirstOrDefault();
List<ModelCurve> curves = new();
IEnumerable<bool> gridGroups = grids
.GroupBy(g => g.Curve.ComputeDerivatives(0, true).BasisX.Normalize().X)
.Select(s => s.Count() > 1);
Plane plane = Plane.CreateByOriginAndBasis(XYZ.Zero, XYZ.BasisX, XYZ.BasisY);
SketchPlane sketch = SketchPlane.Create(Document, plane);
foreach (Grid grid in grids)
{
Curve curve = grid.Curve;
XYZ startp = curve.GetEndPoint(0);
XYZ endp = curve.GetEndPoint(1);
int radius = 2;
XYZ direction = curve.ComputeDerivatives(0, true).BasisX.Normalize().Negate();
XYZ direction1 = curve.ComputeDerivatives(1, true).BasisX.Normalize();
SketchPlane gridSketch = SketchPlane.Create(Document, new Reference(grid));
XYZ loc = startp + (direction * radius);
XYZ loc1 = endp + (direction1 * radius);
Arc circle = Arc.Create(loc, radius, 0, Math.PI * 2, XYZ.BasisX, XYZ.BasisY);
Arc circle1 = Arc.Create(loc1, radius, 0, Math.PI * 2, XYZ.BasisX, XYZ.BasisY);
TextNoteOptions options =
new(textnotetype.Id)
{
HorizontalAlignment = HorizontalTextAlignment.Center,
#if REVIT2019 || REVIT2020
VerticalAlignment = VerticalTextAlignment.Middle
#endif
};
//Text.FromStringOriginAndScale(grid.Name, loc, size);
//Text.FromStringOriginAndScale(grid.Name, loc1, size);
TextNote.Create(Document, view.Id, loc, grid.Name, options);
TextNote.Create(Document, view.Id, loc1, grid.Name, options);
ModelCurve gridLine = Document.Create.NewModelCurve(grid.Curve, gridSketch);
Document.Create.NewModelCurve(circle, sketch);
Document.Create.NewModelCurve(circle1, sketch);
curves.Add(gridLine);
}
return curves;
}
internal static MethodInfo GenerateTransientDisplayMethod()
{
Type geometryElementType = typeof(GeometryElement);
MethodInfo[] geometryElementTypeMethods = geometryElementType.GetMethods(
BindingFlags.Static | BindingFlags.Public | BindingFlags.NonPublic
);
MethodInfo method = geometryElementTypeMethods.FirstOrDefault(x => x.Name == "SetForTransientDisplay");
return method;
}
private ReferenceArray RemoveZeroSegements(Wall wall, ReferenceArray wallLengthRefernceArray, Dimension lengthdim)
{
List<Reference> referencesdelete = new();
ReferenceArray finallengthreferenceArray = new();
for (int i = 0; i < lengthdim.NumberOfSegments; i++)
{
if (lengthdim.Segments.get_Item(i).ValueString == "0")
{
if (lengthdim.References.get_Item(i).ElementId == wall.Id)
{
referencesdelete.Add(lengthdim.References.get_Item(i));
}
if (lengthdim.References.get_Item(i + 1).ElementId == wall.Id)
{
referencesdelete.Add(lengthdim.References.get_Item(i + 1));
}
}
}
for (int i = 0; i < wallLengthRefernceArray.Size; i++)
{
bool isContain = false;
Reference reference = wallLengthRefernceArray.get_Item(i);
foreach (Reference referdelete in referencesdelete)
{
if (reference.EqualTo(referdelete))
{
isContain = true;
}
}
if (!isContain)
{
finallengthreferenceArray.Append(reference);
}
}
return finallengthreferenceArray;
}
public void CreateBeamsDimension(Document Document)
{
FilteredElementCollector col = new(Document, Document.ActiveView.Id);
ElementCategoryFilter categoryFilter1 = new(BuiltInCategory.OST_StructuralFraming);
col.WherePasses(categoryFilter1);
IEnumerable<Element> beams = col.GroupBy(g => g.Name).Select(s => s.FirstOrDefault());
foreach (FamilyInstance familyInstance in beams)
{
XYZ loc = (familyInstance.Location as LocationPoint).Point;
List<Face> faces = GetSideFacesByElement(familyInstance);
if (faces.Count == 0) //找不到实例的几何元素时,需从类型集合查找
{
Options options = new() { ComputeReferences = true };
faces = GetFacesByFamilyInstance(familyInstance, options);
for (int i = faces.Count - 1; i >= 0; i--)
{
PlanarFace pf = faces[i] as PlanarFace;
if (pf.FaceNormal.CrossProduct(XYZ.BasisZ).IsAlmostEqualTo(XYZ.Zero))
{
faces.Remove(faces[i]); //移除顶面底面
}
}
}
ReferenceArray referenceArray = new();
ReferenceArrayArray referenceArrayArray = new();
GetParallFacesReferenceArray(faces, faces.FirstOrDefault(), referenceArray, referenceArrayArray);
foreach (ReferenceArray array in referenceArrayArray)
{
PlanarFace face = familyInstance.GetGeometryObjectFromReference(array.get_Item(0)) as PlanarFace;
Line line = Line.CreateUnbound(loc, face.FaceNormal).CreateOffset(600 / 304.8, XYZ.BasisZ) as Line;
Document.Create.NewDimension(Document.ActiveView, line, array);
}
}
}
public void CreateColumnsDimension(Document Document, View view)
{
FilteredElementCollector col = new(Document, view.Id);
ElementCategoryFilter categoryFilter1 = new(BuiltInCategory.OST_StructuralColumns);
ElementCategoryFilter categoryFilter2 = new(BuiltInCategory.OST_Columns);
LogicalOrFilter andFilter = new(categoryFilter1, categoryFilter2);
col.WherePasses(andFilter);
IEnumerable<Element> columns = col.GroupBy(g => g.Name).Select(s => s.FirstOrDefault());
foreach (FamilyInstance familyInstance in columns)
{
XYZ loc = (familyInstance.Location as LocationPoint).Point;
List<Face> faces = GetSideFacesByElement(familyInstance);
if (faces.Count == 0) //找不到实例的几何元素时,需从类型集合查找
{
Options options = new() { ComputeReferences = true };
faces = GetFacesByFamilyInstance(familyInstance, options);
for (int i = faces.Count - 1; i >= 0; i--)
{
if (faces[i] is PlanarFace)
{
PlanarFace pf = faces[i] as PlanarFace;
if (pf.FaceNormal.CrossProduct(XYZ.BasisZ).IsAlmostEqualTo(XYZ.Zero))
{
faces.Remove(faces[i]); //移除顶面底面
}
}
}
}
ReferenceArray referenceArray = new();
ReferenceArrayArray referenceArrayArray = new();
GetParallFacesReferenceArray(faces, faces.FirstOrDefault(), referenceArray, referenceArrayArray);
foreach (ReferenceArray array in referenceArrayArray)
{
if (array.Size == 0)
{
continue;
}
PlanarFace face = familyInstance.GetGeometryObjectFromReference(array.get_Item(0)) as PlanarFace;
Line line = Line.CreateUnbound(loc, face.FaceNormal).CreateOffset(600 / 304.8, XYZ.BasisZ) as Line;
Document.Create.NewDimension(Document.ActiveView, line, array);
}
}
}
private void CreateDimension(Document Document, View view, List<ModelCurve> mcurves)
{
List<Curve> lines = mcurves.Where(c => c is ModelLine).Select(mc => mc.GeometryCurve).ToList();
List<List<Curve>> groups = new();
GetParallLineGroups(lines, groups);
foreach (List<Curve> g in groups)
{
List<Line> gx = g.ConvertAll(x => x as Line);
if (!gx.Any())
{
continue;
}
XYZ direction = gx.FirstOrDefault()?.Direction;
//IOrderedEnumerable<Line> orderedlist = null;
//if (direction.AngleTo(XYZ.BasisX) >= direction.AngleTo(XYZ.BasisY))
//{
// orderedlist = gx.OrderBy(l => l.Direction.X);
//}
//else
//{
// orderedlist = gx.OrderBy(l => l.Direction.Y);
//}
if (g.Count <= 1)
{
continue;
}
Line line =
Line.CreateUnbound(g.FirstOrDefault()?.GetEndPoint(0), direction.CrossProduct(XYZ.BasisZ))
.CreateOffset(1500 / 304.8, XYZ.BasisZ) as Line;
Line line1 =
Line.CreateUnbound(g.FirstOrDefault()?.GetEndPoint(1), direction.CrossProduct(XYZ.BasisZ))
.CreateOffset(1500 / 304.8, XYZ.BasisZ) as Line;
ReferenceArray arrayAll = new();
foreach (Curve l in g)
{
arrayAll.Append(l.Reference);
}
Dimension dimension1 = Document.Create.NewDimension(view, line, arrayAll);
Dimension dimension2 = Document.Create.NewDimension(view, line1, arrayAll);
Document.Regenerate();
Line line3 =
Line.CreateUnbound(g.FirstOrDefault()?.GetEndPoint(0), direction.CrossProduct(XYZ.BasisZ))
.CreateOffset(1000 / 304.8, XYZ.BasisZ) as Line;
Line line4 =
Line.CreateUnbound(g.FirstOrDefault()?.GetEndPoint(1), direction.CrossProduct(XYZ.BasisZ))
.CreateOffset(1000 / 304.8, XYZ.BasisZ) as Line;
ReferenceArray array = new();
array.Append(dimension1.References.get_Item(0));
array.Append(dimension1.References.get_Item(arrayAll.Size - 1));
Document.Create.NewDimension(view, line3, array);
Document.Create.NewDimension(view, line4, array);
Document.Regenerate();
}
}
private void CreateWallDimension(Document Document, View view)
{
FilteredElementCollector wallCol = new FilteredElementCollector(Document, view.Id).OfClass(typeof(Wall));
foreach (Wall wall in wallCol)
{
if (wall.WallType.Kind != WallKind.Basic)
{
continue;
}
LocationCurve loc = wall.Location as LocationCurve;
ReferenceArray wallThickReferenceArray = new();
ReferenceArray wallLengthRefernceArray = new();
List<Face> faces = GetSideFacesByElement(wall);
foreach (Face face in faces)
{
PlanarFace pf = face as PlanarFace;
if (pf == null || face.Reference == null || pf.OrientationMatchesSurfaceOrientation == false)
{
continue;
}
if (pf.FaceNormal.CrossProduct(wall.Orientation).IsAlmostEqualTo(XYZ.Zero))
{
if (Document.GetElement(face.Reference).Id == wall.Id)
{
wallThickReferenceArray.Append(face.Reference);
}
}
else if (pf.FaceNormal.DotProduct(wall.Orientation) < 0.001)
{
wallLengthRefernceArray.Append(face.Reference);
}
}
try
{
int scale = Document.ActiveView.Scale;
Autodesk.Revit.DB.Transform tranform = Autodesk.Revit.DB.Transform.CreateTranslation(
wall.Orientation * scale * 15 / 304.8
);
Line wallcurve = (wall.Location as LocationCurve).Curve as Line;
Line lengthLine = wallcurve.CreateTransformed(tranform) as Line;
Dimension lengthdim = Document.Create.NewDimension(Document.ActiveView, lengthLine, wallLengthRefernceArray);
Document.Regenerate();
ReferenceArray finallengthreferenceArray = RemoveZeroSegements(wall, wallLengthRefernceArray, lengthdim);
Document.Delete(lengthdim.Id);
Document.Create.NewDimension(Document.ActiveView, lengthLine, finallengthreferenceArray);
Line thickLine = Line.CreateUnbound(wallcurve.Evaluate(0.2, true), wall.Orientation);
Dimension thickdim = Document.Create.NewDimension(Document.ActiveView, thickLine, wallThickReferenceArray);
if (lengthdim.Segments.Size > 2)
{
ReferenceArray referenceArray = new();
Reference refer1 = lengthdim.References.get_Item(0);
Reference refer2 = lengthdim.References.get_Item(lengthdim.References.Size - 1);
referenceArray.Append(refer1);
referenceArray.Append(refer2);
Autodesk.Revit.DB.Transform tranform1 = Autodesk.Revit.DB.Transform.CreateTranslation(
wall.Orientation * scale * 25 / 304.8
);
Line lengthLine1 = wallcurve.CreateTransformed(tranform1) as Line;
Document.Create.NewDimension(Document.ActiveView, lengthLine1, referenceArray);
}
}
catch (Exception) { }
}
}
public void GetParallFacesReferenceArray(
List<Face> faces,
Face firstFace,
ReferenceArray referenceArray,
ReferenceArrayArray referenceArrayArray
)
{
if (referenceArrayArray.Size == 0)
{
referenceArrayArray.Append(referenceArray);
}
for (int i = 0; i < faces.Count; i++)
{
if (faces[i] is not PlanarFace)
{
continue;
}
PlanarFace tempFace = faces[i] as PlanarFace;
PlanarFace pf = firstFace as PlanarFace;
XYZ facenormal = pf.FaceNormal;
//把初始的第一个添加进集合
if (tempFace.FaceNormal.CrossProduct(facenormal).IsAlmostEqualTo(XYZ.Zero))
{
referenceArray.Append(tempFace.Reference);
faces.Remove(tempFace);
GetParallFacesReferenceArray(faces, tempFace, referenceArray, referenceArrayArray);
}
if (i == faces.Count() - 1)
{
referenceArray = new ReferenceArray();
GetParallFacesReferenceArray(faces, faces.FirstOrDefault(), referenceArray, referenceArrayArray);
if (!faces.Any())
{
referenceArrayArray.Append(referenceArray);
}
}
}
}
/// <summary>
/// 递归找到所有平行线集合
/// </summary>
public static void GetParallLineGroups(List<Curve> lines, List<List<Curve>> groups)
{
Curve firstLine = lines.FirstOrDefault();
lines = lines.FindAll(curve => curve is Line);
List<Curve> group = new() { firstLine };
groups.Add(group);
Line line = firstLine as Line;
lines.Remove(firstLine);
for (int i = lines.Count - 1; i >= 0; i--)
{
if (lines[i] is not Line)
{
continue;
}
Line tempLine = lines[i] as Line;
if (
tempLine.Direction.CrossProduct(line.Direction).IsAlmostEqualTo(XYZ.Zero)
&& Math.Abs(tempLine.Length - line.Length) < 0.00001
)
{
group.Add(tempLine);
lines.Remove(tempLine);
//GetParallFaces(faces, tempFace, ZoomRBGroup, groups);
}
}
if (lines.Count >= 1)
{
GetParallLineGroups(lines, groups);
}
}
private void TransientGrid(Document Document, Grid grid)
{
double radius = 1.5;
double size = 1.8;
XYZ startp = grid.Curve.GetEndPoint(0);
XYZ endp = grid.Curve.GetEndPoint(1);
XYZ direction = grid.Curve.ComputeDerivatives(0, true).BasisX.Normalize().Negate();
XYZ direction1 = grid.Curve.ComputeDerivatives(1, true).BasisX.Normalize();
XYZ loc = startp + (direction * radius);
XYZ loc1 = endp + (direction1 * radius);
IEnumerable<Curve> text = Text.FromStringOriginAndScale(grid.Name, loc, size);
IEnumerable<Curve> text1 = Text.FromStringOriginAndScale(grid.Name, loc1, size);
Arc circle = Arc.Create(loc, radius, 0, Math.PI * 2, XYZ.BasisX, XYZ.BasisY);
Arc circle1 = Arc.Create(loc1, radius, 0, Math.PI * 2, XYZ.BasisX, XYZ.BasisY);
List<GeometryObject> geoms = new() { grid.Curve, circle, circle1 };
geoms.AddRange(text);
geoms.AddRange(text1);
MethodInfo method = GenerateTransientDisplayMethod();
object[] argsM = new object[4];
argsM[0] = Document;
argsM[1] = ElementId.InvalidElementId;
argsM[2] = geoms;
argsM[3] = ElementId.InvalidElementId;
ElementId transientElementId = (ElementId)method.Invoke(null, argsM);
MessageBox.Show(transientElementId.IntegerValue.ToString(), "元素ID");
//doc.Delete(transientElementId);
}
}
public class TransientElementMaker : ITransientElementMaker
{
private readonly Document _document;
public List<GeometryObject> GeometryObjects { get; set; }
public TransientElementMaker(Document document)
{
_document = document;
}
public void Execute()
{
if (GeometryObjects != null)
{
DirectShape ds = DirectShape.CreateElement(_document, new ElementId(BuiltInCategory.OST_GenericModel));
//CreateUtils.CreateCube(), CreateUtils.CreateSphere()为创建一个立方体与球体Solid,文略
//ds.AppendShape(GeometryObjects);
ds.AppendShape(new List<GeometryObject> { CreateCube() });
}
}
public Solid CreateCube()
{
CurveLoop cubeBaseLines = new();
cubeBaseLines.Append(Line.CreateBound(new XYZ(0, 0, 0), new XYZ(100, 0, 0)));
cubeBaseLines.Append(Line.CreateBound(new XYZ(100, 0, 0), new XYZ(100, 100, 0)));
cubeBaseLines.Append(Line.CreateBound(new XYZ(100, 100, 0), new XYZ(0, 100, 0)));
cubeBaseLines.Append(Line.CreateBound(new XYZ(0, 100, 0), new XYZ(0, 0, 0)));
Solid solidCube = GeometryCreationUtilities.CreateExtrusionGeometry(new List<CurveLoop> { cubeBaseLines }, XYZ.BasisZ, 100);
return solidCube;
}
}
public static class Text
{
public static IEnumerable<Curve> FromStringOriginAndScale(string text, XYZ origin, double scale)
{
//http://msdn.microsoft.com/en-us/library/ms745816(v=vs.110).aspx
List<Curve> crvs = new();
FontFamily font = new("Arial");
FontStyle fontStyle = FontStyles.Normal;
FontWeight fontWeight = FontWeights.Medium;
//if (Bold == true) fontWeight = FontWeights.Bold;
//if (Italic == true) fontStyle = FontStyles.Italic;
// Create the formatted text based on the properties set.
#if REVIT2019||REVIT2020
System.Windows.Media.FormattedText formattedText =
new(
text,
CultureInfo.GetCultureInfo("en-us"),
FlowDirection.LeftToRight,
new Typeface(font, fontStyle, fontWeight, FontStretches.Normal),
1,
Brushes.Black,
1 // This brush does not matter since we use the geometry of the text.
);
#elif REVIT2018
var formattedText = new System.Windows.Media.FormattedText(
text,
CultureInfo.GetCultureInfo("en-us"),
FlowDirection.LeftToRight,
new Typeface(font, fontStyle, fontWeight, FontStretches.Normal),
1,
Brushes.Black // This brush does not matter since we use the geometry of the text.
,
1.25
);
#endif
// Build the geometry object that represents the text.
Geometry textGeometry = formattedText.BuildGeometry(new System.Windows.Point(0, 0));
foreach (PathFigure figure in textGeometry.GetFlattenedPathGeometry().Figures)
{
System.Windows.Point init = figure.StartPoint;
System.Windows.Point a = figure.StartPoint;
System.Windows.Point b;
foreach (PathSegment segment in figure.GetFlattenedPathFigure().Segments)
{
if (segment is System.Windows.Media.LineSegment lineSeg)
{
b = lineSeg.Point;
Line crv = LineBetweenPoints(origin, scale, a, b);
a = b;
crvs.Add(crv);
}
if (segment is PolyLineSegment plineSeg)
{
foreach (System.Windows.Point segPt in plineSeg.Points)
{
Line crv = LineBetweenPoints(origin, scale, a, segPt);
a = segPt;
crvs.Add(crv);
}
}
}
}
return crvs;
}
private static Line LineBetweenPoints(XYZ origin, double scale, System.Windows.Point a, System.Windows.Point b)
{
XYZ pt1 = new((a.X * scale) + origin.X, ((-a.Y + 1) * scale) + origin.Y, origin.Z);
XYZ pt2 = new((b.X * scale) + origin.X, ((-b.Y + 1) * scale) + origin.Y, origin.Z);
Line crv = Line.CreateBound(pt1, pt2);
return crv;
}
}
}