ImportInstance Polyline Reference

ImportInstance Polyline Reference

Anonymous
Not applicable
2,444 Views
13 Replies
Message 1 of 14

ImportInstance Polyline Reference

Anonymous
Not applicable

What I want to do is align an importinstance derived from an AutoCAD .dwg to a reference plane. 

 

My attempt at this was to access the import instance's geometry objects and find a valid line reference to align to the reference plane. When there are single lines in the dwg this works fine.

 

However it appears that when there are contiguous lines, a Polyline is created in the import instance geometry. Is there any way to obtain one of the line references within a polyline? (the line in question is highlighted in blue in the image but is a part of a polyline)

adelira_0-1614630063024.png

 

I also tried selecting the lines with uidoc.Selection.PickObject but I wasn't able to select the reference for the line I want. (I was getting the polyline reference)

Reference r = uidoc.Selection.PickObject(
                ObjectType.PointOnElement, 
                new ImportSelectionFilter(),
                "Please pick an element in an imported object");

public class ImportSelectionFilter : ISelectionFilter
        {
            public bool AllowElement(Element elem)
            {
                return elem.GetType() == typeof(ImportInstance);
            }
            public bool AllowReference(Reference refer, XYZ pos)
            {
                return true;
            }
        }

adelira_1-1614630129251.png

 

Anything simple I'm missing here?

Thank you

 

 

0 Likes
2,445 Views
13 Replies
Replies (13)
Message 2 of 14

Anonymous
Not applicable

Also here is how I was obtaining the lines of the import.

Options DefaultOptions = new Options();
DefaultOptions.ComputeReferences = true;
DefaultOptions.IncludeNonVisibleObjects = true;
var geometry_lines = (import_in_view
    .get_Geometry(DefaultOptions)
    .FirstOrDefault() as GeometryInstance)
    .GetSymbolGeometry()
    .OfType<Autodesk.Revit.DB.Line>();

 

0 Likes
Message 3 of 14

RPTHOMAS108
Mentor
Mentor

You can't get line segments from the polyline but you can create new line segments by iterating the polyline points as below. If you want actual references this approach below is not going to help. Best option is to pick the curve and look at the stable representation (if available).

 

You have to extract both lines and polylines and deal with the polylines separately.

 

Lines in CAD link form polylines if the 3 conditions below are met:

1) They join at ends

2) They have consistent layer name (which transfers to the graphics style of the Polyline).

3) They are contained within the same plane

 

 

 

Private Function GetLinesFromRvtPolyline(Doc As Document, PL As PolyLine) As Line()
        Dim LNs As Line() = New Line(PL.NumberOfCoordinates - 2) {}
        For i = 1 To PL.NumberOfCoordinates - 1 'start at 1 end at number of coords - 1 (zero based)
            Dim Pt0 As XYZ = PL.GetCoordinate(i - 1)
            Dim Pt1 As XYZ = PL.GetCoordinate(i)

            Dim LNX As Line = Line.CreateBound(Pt0,Pt1)
            LNs(i - 1) = LNX
        Next
        Return LNs
End Function

 

 

 

0 Likes
Message 4 of 14

Anonymous
Not applicable

I need to lock a cad import instance to a plane so it can move along with a reference plane. I don't want to create any new lines unless they can somehow be used to lock the dwg import instance to the reference plane.

 

0 Likes
Message 5 of 14

RPTHOMAS108
Mentor
Mentor

You can get a reference and you can use that to lock to a reference plane but your main issue is in identifying which reference in the cad import is the one you want to lock to.

 

Perhaps the only way to do this is by using a unique layer name to identify the line in CAD or from identifying line by origin and direction e.g. as measured from line with the minimum X,Y value and same direction as Transform.BasisX of ImportInstance. There is that relationship to pair to two things WCS in CAD and truncated coords of Revit CadLink.

 

Not sure it is possible actually since you can't generate references you can only pick curves to generate them i.e. there is no way to relate the references as they are to their locations.

0 Likes
Message 6 of 14

Anonymous
Not applicable

My workaround would be using a unique layer as you suggested RPTH0MAS108.

 

Hopefully there is some other built in solution though.

0 Likes
Message 7 of 14

FAIR59
Advisor
Advisor

I believe you can with time and effort reverse engineer the structure of the  StableRepresentation of references to a CADImport ( references from (manual) placed dimensions ). With that knowledge you can then construct your own references using  Reference.ParseFromStableRepresentation().

There is however an easier approach :

Load the CAD into a nested family and use the referenceplanes from the nested family to position the CAD in the main family.

0 Likes
Message 8 of 14

RPTHOMAS108
Mentor
Mentor

I think the main challenge is how you relate a known location in CAD to a geometry reference in Revit.

 

I think your would have to create some kind of intersection result based on points near the curve in Revit to obtain the reference.

 

I think you are right other ways are probably easier. Also considered grouping a model curve overlaid with the link and aligning using that.

0 Likes
Message 9 of 14

Anonymous
Not applicable

Using convert to stable representation is an interesting idea.

 

Following https://thebuildingcoder.typepad.com/blog/2016/04/stable-reference-string-magic-voodoo.html i've determined that in the following string, the "token" before LINEAR (150 in the below string) determines which line object in the table of geometry objects is referenced.

 

"19fd9de5-3810-4f65-be2c-ac9b6342f998-00117ce8:0:INSTANCE:19fd9de5-3810-4f65-be2c-ac9b6342f998-00117ce7:203:150:LINEAR"

 

By modifying the token I can actually create a reference to a polyline. Going to experiment a bit more and see what I can do.

0 Likes
Message 10 of 14

Anonymous
Not applicable

Got it to work sort of!

 

Essentially I just tried iterating through all possible storage index of the reference string representation for the import instance and tried using the references from Reference.ParseFromStableRepresentation. Eventually I found a refernce that actually worked with doc.FamilyCreate.NewAlignment. Now its just a matter of filtering out the correct reference.

 

Thanks again for your suggestions. Going to post if I make any more progress.

 

var import_in_view = new FilteredElementCollector(doc)
    .OfClass(typeof(ImportInstance))
    .OfType<ImportInstance>()
    .FirstOrDefault();
GetGeometryReferences(import_in_view, doc);

var imp_ref = new Reference(import_in_view);
var stable_rep = imp_ref.ConvertToStableRepresentation(doc);
var reference_plane = new FilteredElementCollector(doc)
    .OfClass(typeof(ReferencePlane))
    .OfType<ReferencePlane>()
    .FirstOrDefault(plane =>
        plane.Name.Equals(
            "MullionOffset",
             StringComparison.OrdinalIgnoreCase));

bool success = false;
using (var tx = new Transaction(doc, "create curves"))
{
    tx.Start();
    foreach (var geo_ref in GeometryReferences)
    {
        try
        {
            var polyline_ref = geo_ref.Value.reference;
            doc.FamilyCreate.NewAlignment(
                doc.ActiveView,
                reference_plane.GetReference(),
                polyline_ref);
            success = true;
            break;
        }
        catch { }
    }
    tx.Commit();
}


        public class GeometryReference
        {
            public Reference reference;
            public GeometryObject geometryObject;
            public string stableRepresentation;
        }
        public Dictionary<int, GeometryReference> GeometryReferences = 
            new Dictionary<int, GeometryReference>();
        public void GetGeometryReferences(
            ImportInstance import_instance,
            Document doc)
        {
            Options DefaultOptions = new Options();
            DefaultOptions.ComputeReferences = true;
            DefaultOptions.IncludeNonVisibleObjects = true;
            DefaultOptions.DetailLevel = doc.ActiveView.DetailLevel;

            var geometry = (import_instance
                .get_Geometry(DefaultOptions)
                .FirstOrDefault() as GeometryInstance)
                .GetSymbolGeometry();
            var linear_string = geometry
                .OfType<Autodesk.Revit.DB.Line>()
                .FirstOrDefault()
                .Reference
                .ConvertToStableRepresentation(doc);
            var index = 5;
            var parted_string = linear_string.Split(':')[index];
            var other_part = linear_string.Split(':')[index-1];
            var part_to_replace = other_part + ":" + parted_string;

            int ctr = 1;
            for(int i=0; i<1000; i++)
            {
                for(int j=0; j<1000; j++)
                {
                    var object_string = linear_string.Replace(
                        part_to_replace,
                        i.ToString()+":"+j.ToString());
                    var object_ref = Reference.ParseFromStableRepresentation(
                    doc,
                    object_string);
                    var geometry_object = import_instance
                        .GetGeometryObjectFromReference(object_ref);
                    //if (geometry_object is Autodesk.Revit.DB.Line)
                    //{
                        GeometryReferences.Add(
                            ctr,
                            new GeometryReference()
                            {
                                geometryObject = geometry_object,
                                reference = object_ref,
                                stableRepresentation = object_string
                            });
                        ctr++;
                    //}
                }
            }
        }

 

 

0 Likes
Message 11 of 14

Anonymous
Not applicable

Turns out the reference that worked returned an Edge geometry object with 
Element.GetGeometryObjectFromReference().

 

 

adelira_0-1614715915295.png

 

By changing the code in my previous reply to filter for edges i can filter through all the possibilities way faster. 

 

0 Likes
Message 12 of 14

Anonymous
Not applicable

Not the cleanest solution but this seems to work. What I do is iterate through the stable representation "containers" until I find edges. Then i find the edge that is coincident with the plane I want to lock to.

 

Again, thanks for your suggestions.

 

var doc = uidoc.Document;

var import_in_view = new FilteredElementCollector(doc)
    .OfClass(typeof(ImportInstance))
    .OfType<ImportInstance>()
    .FirstOrDefault();

var reference_plane = new FilteredElementCollector(doc)
    .OfClass(typeof(ReferencePlane))
    .OfType<ReferencePlane>()
    .FirstOrDefault(plane =>
        plane.Name.Equals(
            "MullionOffset",
            StringComparison.OrdinalIgnoreCase));

var plane_pt1 = reference_plane.FreeEnd.Project(doc.ActiveView);
var plane_pt2 = reference_plane.BubbleEnd.Project(doc.ActiveView);
var plane_line = Line.CreateBound(
    plane_pt1,
    plane_pt2);

var edge_references = GetGeometryReferences(
    import_in_view,
    doc);
var cooincident_edge_references = edge_references
    .Where(edge_ref =>
        edge_ref
            .curve
            .Intersect(plane_line)
            .Equals(SetComparisonResult.Equal));
if (cooincident_edge_references.Count() > 0)
{
    using (var tx = new Transaction(doc, "create curves"))
    {
        tx.Start();
        doc.FamilyCreate.NewAlignment(
            doc.ActiveView,
            reference_plane.GetReference(),
            cooincident_edge_references
                .FirstOrDefault()
                .reference);
         tx.Commit();
    }
}

 

public class EdgeReference
{
    public Reference reference;
    public Curve curve;
}
public HashSet<EdgeReference> GetGeometryReferences(
    ImportInstance import_instance,
    Document doc)
{
    Options DefaultOptions = new Options();
    DefaultOptions.ComputeReferences = true;
    DefaultOptions.IncludeNonVisibleObjects = true;
    DefaultOptions.DetailLevel = doc.ActiveView.DetailLevel;

    var edgeReferences = new HashSet<EdgeReference>();

    var geometry = (import_instance
        .get_Geometry(DefaultOptions)
        .FirstOrDefault() as GeometryInstance)
        .GetSymbolGeometry();
    var linear_string = geometry
        .OfType<Autodesk.Revit.DB.Line>()
        .FirstOrDefault()
        .Reference
        .ConvertToStableRepresentation(doc);
    var index = 5;
    var item_index = linear_string
        .Split(':')[index];
    var container_index = linear_string
        .Split(':')[index-1];
    var part_to_replace = container_index + 
        ":" + 
        item_index;

    //check the container line was found in for edges
    for (int i = 1; i < 1000; i++)
    {
        var object_string = linear_string.Replace(
            item_index,
            i.ToString());
        var object_ref = Reference.ParseFromStableRepresentation(
                doc,
                object_string);
        var geometry_object = import_instance
                    .GetGeometryObjectFromReference(object_ref);
        if (geometry_object is Autodesk.Revit.DB.Edge)
        {
                    edgeReferences.Add(
                        new EdgeReference()
                        {
                            curve = (geometry_object as Edge).AsCurve(),
                            reference = object_ref
                        });
         }
   }
   //check the other containers
   for(int i=1; i< geometry.Count(); i++)
   {
       bool found_item = false;
       for(int j=1; j< geometry.Count(); j++)
       {
           var object_string = linear_string.Replace(
               part_to_replace,
               i.ToString()+":"+j.ToString());
           var object_ref = Reference.ParseFromStableRepresentation(
               doc,
               object_string);
           var geometry_object = import_instance
                .GetGeometryObjectFromReference(object_ref);
            if (found_item && geometry_object == null)
                break;
            if (!found_item && geometry_object!=null )
            {
                found_item = true;
            }
            if (geometry_object is Autodesk.Revit.DB.Edge)
            {
                edgeReferences.Add(
                    new EdgeReference()
                            {
                                curve = (geometry_object as Edge).AsCurve(),
                                reference = object_ref
                            });
            }
        }
    }
    return edgeReferences;
}

 

0 Likes
Message 13 of 14

Anonymous
Not applicable

Doing this seems to have issues as well... Sometimes it works fine other times I can't find the reference I need.

Theres a good chance I will end up just drawing a single line on a unique layer in AutoCAD. 

 

0 Likes
Message 14 of 14

sonvu240598
Explorer
Explorer
Is that you convert DWG to edges
0 Likes