Dynamically space elements with a given value along a host

Dynamically space elements with a given value along a host

george.potts
Enthusiast Enthusiast
227 Views
1 Reply
Message 1 of 2

Dynamically space elements with a given value along a host

george.potts
Enthusiast
Enthusiast

Hello all,

 I am trying to create a dynamic element spacer with a given space. I have some logic that sorts elements into a order based on their points horiz or vert.

 

I have center to center working as I'd like, but like anything in modelling, this is not all that useful. The current code has the user give a spacing value, then select their spacing logic.

 

I am currently getting the user to select the faces, I can write some code to dynamically detect the closest space (draft below)  later down the line, once I have some reliable spacing maths.

 

public static Face GetClosestFaceToPoint(Element element, XYZ referencePoint)
    {
        if (element == null || referencePoint == null)
            return null;

        Options geomOptions = new Options
        {
            ComputeReferences = true,
            IncludeNonVisibleObjects = false,
            DetailLevel = ViewDetailLevel.Fine
        };

        GeometryElement geometry = element.get_Geometry(geomOptions);
        if (geometry == null)
            return null;

        Face closestFace = null;
        double minDistance = double.MaxValue;

        foreach (GeometryObject geomObj in geometry)
        {
            Solid solid = geomObj as Solid;

            // Handle GeometryInstances (symbol geometry)
            if (geomObj is GeometryInstance instance)
            {
                foreach (GeometryObject instObj in instance.GetInstanceGeometry())
                {
                    solid = instObj as Solid;
                    if (solid != null)
                        EvaluateFaces(solid, referencePoint, ref closestFace, ref minDistance);
                }
            }
            else if (solid != null)
            {
                EvaluateFaces(solid, referencePoint, ref closestFace, ref minDistance);
            }
        }

        return closestFace;
    }

    private static void EvaluateFaces(Solid solid, XYZ referencePoint, ref Face closestFace, ref double minDistance)
    {
        foreach (Face face in solid.Faces)
        {
            IntersectionResult result = face.Project(referencePoint);
            if (result != null)
            {
                double distance = result.XYZPoint.DistanceTo(referencePoint);
                if (distance < minDistance)
                {
                    minDistance = distance;
                    closestFace = face;
                }
            }
        }
    }


Here is my source code:

 

if (CenterToCenter)
{
    XYZ prevCenter = ordered[0].Center;

    for (int i = 1; i < ordered.Count; i++)
    {
        using (Transaction tx = new Transaction(doc, "Move CenterToCenter Element"))
        {
            tx.Start();

            AnnotationElement currElem = ordered[i];
            XYZ currCenter = currElem.Center;

            XYZ target;
            if (isVertical)
                target = new XYZ(prevCenter.X, prevCenter.Y - spacingInFeet, prevCenter.Z);
            else
                target = new XYZ(prevCenter.X + spacingInFeet, prevCenter.Y, prevCenter.Z);

            XYZ moveVec = target - currCenter;
            ElementTransformUtils.MoveElement(doc, currElem.Id, moveVec);

            prevCenter = target;
            tx.Commit();
        }
    }
}

if (FaceToFace)
{
    XYZ basePoint = XYZ.Zero;
    XYZ baseDirection = XYZ.BasisX;
    XYZ secondPoint = XYZ.Zero;

    for (int i = 0; i < ordered.Count; i++)
    {
        if (i == 0)
        {
            TaskDialog.Show("Face Selection", $"Select face point on element {i + 1} (anchor)");
            Reference refAnchor = uiApp.ActiveUIDocument.Selection.PickObject(ObjectType.Face, "Click a point on face of the FIRST (fixed) element");
            basePoint = refAnchor.GlobalPoint;

            TaskDialog.Show("Face Selection", $"Select face point on element {i + 2}");
            Reference refSecond = uiApp.ActiveUIDocument.Selection.PickObject(ObjectType.Face, "Click a point on face of the SECOND element");
            secondPoint = refSecond.GlobalPoint;

            XYZ direction = (secondPoint - basePoint).Normalize();

            if (isVertical)
                direction = new XYZ(0, direction.Y, 0);
            else
                direction = new XYZ(direction.X, 0, 0);

            baseDirection = direction;

            continue; // Don't move the anchor element
        }

        Element elementToMove = ordered[i].Parent;

        XYZ currentPoint;

        if (i == 1)
        {
            currentPoint = secondPoint;
        }
        else
        {
            TaskDialog.Show("Face Selection", $"Select face point on element {i + 1}");
            Reference refFace = uiApp.ActiveUIDocument.Selection.PickObject(ObjectType.Face, "Click a point on face of the element");
            currentPoint = refFace.GlobalPoint;
        }

        XYZ targetPoint = basePoint + (baseDirection * (spacingInFeet * i));

        XYZ moveVec = targetPoint - currentPoint;

        Debug.WriteLine($"Target Point: {targetPoint}");
        Debug.WriteLine($"Current Point: {currentPoint}");
        Debug.WriteLine($"Move Vector: {moveVec}");

        using (Transaction tx = new Transaction(doc, $"Move Element {i + 1}"))
        {
            tx.Start();
            ElementTransformUtils.MoveElement(doc, elementToMove.Id, moveVec);
            tx.Commit();
        }
    }
}



The current problem is this: the distance between the selected faces, is not equal to my spacing value. It seems to be more reliable at lower numbers, like 25, but not so reliable at 150, equalling 148.


Does anyone have any suggestions on what to try? 

0 Likes
228 Views
1 Reply
Reply (1)
Message 2 of 2

george.potts
Enthusiast
Enthusiast

bump

0 Likes