Jump to content
Developer Wiki and Function Reference Links ×

Collinear lines that either touch, overlap, or are superimposed


Recommended Posts

I am a beginner with the Marionette tool, but I would like to create a network that allows me to find collinear lines that either touch, overlap, or are superimposed within a group of objects, and then delete them and replace them with a single line covering the total distance. I'm not sure if I'm being clear ^^ Thanks in advance for your help!

  • Like 1
Link to comment
  • Marionette Maven

This sounds like a fun exercise!
Could you clarify if the object types are actually all lines, or if they might be polylines/polygons? are they always 2D objects?

This is definitely doable, but may require some custom nodes and edge-case handling. Happy to help you work through it!

  • Like 3
Link to comment

Hi Etienne,

 

I'm so onboard with Marionette. I love it for all the visual things. I'm just not super all over it for Global Activities, like the one you're suggesting.

I'm definitely not saying not to in this case, and the things that @Marissa Farrell continually changes my perspective on this I'm grateful for, however as a comparative math operation like this I typically do it in Vectorscript or Python.

 

An example of which is below that I just whipped up and did some tests to take this:

 

Screenshot2025-02-13at12_12_38pm.thumb.png.a84256f709bc8bb79a378ff95c885619.png

 

Into this [Purple are newly created merged lines]:

 

Screenshot2025-02-13at12_12_45pm.thumb.png.d63a5dea80ddd45815c1f3fe226d3c0a.png

 

Presuming this is your request understood correctly the Logic here is pretty straight forward;

  1. Find any two lines (H1 and H2 in this case).
  2. Find their Start and End Points.
  3. Find their Vectors (directions)
  4. If [ the Start AND End of H2 is within the Start and End of H1 ] AND [ the vector of H1 and H2 are the same ] then H2 can be deleted.
  5. If [ the Start OR End of H2 is within the Start and End of H1 ] AND [ the vector of H1 and H2 are the same ] the H2 must be a continuation of H1.
    • Find out if H2 is the Start or End of H1 and then create a new line to cover the whole length.
  6. Rinse and repeat until there are no more line.

 

Vectorscript Code Example:

{ James Russell FEB 2025 }
{ Math and logic by me, code layout thanks to ChatGTP... because I'm time poor. }

PROCEDURE ConsolidateLines;
VAR
    h1, h2, hNew: HANDLE;
    x1a, y1a, x2a, y2a: REAL;
    x1b, y1b, x2b, y2b: REAL;
    merged: BOOLEAN;

FUNCTION HasSameVector(x1a, y1a, x2a, y2a, x1b, y1b, x2b, y2b: REAL): BOOLEAN;
BEGIN
    { Two lines have the same vector if their direction vectors are proportional }
    HasSameVector := ((x2a - x1a) * (y2b - y1b) = (y2a - y1a) * (x2b - x1b));
END;

FUNCTION FullyContains(x1a, y1a, x2a, y2a, x1b, y1b, x2b, y2b: REAL): BOOLEAN;
BEGIN
    { Check if the second line is fully inside the first line and has the same vector }
    FullyContains := (x1b >= x1a) AND (y1b >= y1a) AND (x2b <= x2a) AND (y2b <= y2a)
                     AND HasSameVector(x1a, y1a, x2a, y2a, x1b, y1b, x2b, y2b);
END;

FUNCTION Overlaps(x1a, y1a, x2a, y2a, x1b, y1b, x2b, y2b: REAL): BOOLEAN;
VAR
    minAx, maxAx, minBx, maxBx, minAy, maxAy, minBy, maxBy: REAL;
BEGIN
    { Get bounding values for both lines }
    minAx := Min(x1a, x2a); maxAx := Max(x1a, x2a);
    minBx := Min(x1b, x2b); maxBx := Max(x1b, x2b);
    minAy := Min(y1a, y2a); maxAy := Max(y1a, y2a);
    minBy := Min(y1b, y2b); maxBy := Max(y1b, y2b);
    
    { Overlaps if X and Y ranges intersect }
    Overlaps := (maxAx >= minBx) AND (maxBx >= minAx) AND (maxAy >= minBy) AND (maxBy >= minAy);
END;

BEGIN
    h1 := FInGroup(ActLayer);  { First line }
    WHILE h1 <> NIL DO BEGIN
        IF GetType(h1) = 2 THEN BEGIN  { Ensure it's a line object }
            GetSegPt1(h1, x1a, y1a);
            GetSegPt2(h1, x2a, y2a);
            
            h2 := FInGroup(ActLayer);  { Second line }
            WHILE h2 <> NIL DO BEGIN
                IF (h1 <> h2) AND (GetType(h2) = 2) THEN BEGIN
                    GetSegPt1(h2, x1b, y1b);
                    GetSegPt2(h2, x2b, y2b);
                    
                    merged := FALSE;
                    
                    { If h2 is fully inside h1 and has the same vector, delete h2 }
                    IF FullyContains(x1a, y1a, x2a, y2a, x1b, y1b, x2b, y2b) THEN BEGIN
                        DelObject(h2);
                        merged := TRUE;
                    END;
                    
                    { If h2 overlaps h1 and shares the same vector, merge them }
                    IF Overlaps(x1a, y1a, x2a, y2a, x1b, y1b, x2b, y2b) 
                    AND HasSameVector(x1a, y1a, x2a, y2a, x1b, y1b, x2b, y2b) THEN BEGIN
                        MoveTo(Min(x1a, x1b), Min(y1a, y1b));
                        LineTo(Max(x2a, x2b), Max(y2a, y2b));

                        { Correctly get the last created object }
                        hNew := LNewObj;

                        { Ensure hNew is valid before applying color/thickness }
                        { Remove this section if you don't want your lines coloured - I just did this for the example }
                        IF hNew <> NIL THEN BEGIN
                            SetPenFore(hNew, 50000, 0, 50000);  { Purple }
                            SetLW(hNew, 25);  { 1pt Line Thickness }
                        END;
                        
                        DelObject(h1);
                        DelObject(h2);
                        merged := TRUE;
                    END;
                    
                    IF merged THEN BEGIN
                        h1 := FInGroup(ActLayer);  { Reset loop to check new lines }
                        h2 := NIL;  { Exit inner loop }
                    END ELSE BEGIN
                        h2 := NextObj(h2);  { Move to next line }
                    END;
                END ELSE BEGIN
                    h2 := NextObj(h2);  { Move to next object }
                END;
            END;
        END;
        h1 := NextObj(h1);  { Move to next line }
    END;
END;

RUN(ConsolidateLines);

 

* I'm very sure there are still fringe case in which this doesn't work. It's an example.

** It doesn't work on any curves. You could change it to operate on a different Layer/Group/Selection.

*** I'd still very much like to see a Marionette Network that does this... and might build one later...

 

Anyways, just an option to think about - great question though!

 

Cheers,

 

James

  • Like 2
Link to comment

Hello and thank you for your responses!

Let me give you a bit of context about my work ^^. I’ve been working for two months in a french design office with eight draftsmen who use Vectorworks for a company that cuts PVC fabric and polyurethane foam to create all kinds of products (sports landing mats, ski slope protections, etc.).

For now, I'm not as skilled as they are ^^', but even though each of them has their own specialty, they all go through the same final step in the drawing process: preparing the file for the fabric cutting machine, which cuts rolls of various widths and lengths.

We have a blank Vectorworks file where we paste all our nested fabrics (like Tetris) as groups. They use Vectorworks classes to define the cutting priority order.

- Class 0 is only for the draftsmen and is not taken into account by the machine.

- Classes 8 and 9 are for pen markings on the fabrics before cutting.

Then comes Class 30 for cutting, followed by Class 11, then Class 20, and finally Class 1 as the last cutting phase.

Each of these classes has a specific color.

I'm explaining all this for context because, ideally, I would like to create a Marionette network that follows these steps in this order :

First, the network should recognize the name of the group from the total number of fabric groups.

Then, a first check for the "laize" (the fabric roll width): if the group's width exceeds the predefined width set before executing the script, an error message should appear, and the process cannot continue.

Next, the groups should be ungrouped once, followed by a second collision check for the subgroups:

If the fabrics are just touching, it's OK.

But if they overlap, it means there is a mistake in the nesting done by the draftsman.

Once these two checks are completed, all objects should be ungrouped at least twice and decomposed to keep only lines, texts, arcs, and circles.

After this, I would like to assign the different classes based on colors, but there is one important rule:

The horizontal lines located at the very top or bottom of the width must be in Class 0 (which is not cut), to avoid breaking the machine.

Finally, we reach the main goal: finding the collinear lines that touch, overlap, or are superimposed, as suggested by James Russel! These lines should be deleted and replaced by a single line of the same class.

I know this is a lot to ask :S but you have no idea how much your answers will help me!

However, I’m struggling with Python scripts… Could you send me a Vectorworks file with the Marionette network, or at least a screenshot of the network?

Thank you so much in advance!!!!

image.thumb.png.089de24c1396538d56b2c53e3b12fd3e.png

An example of a file for fabric cutting, ready to be sent in DXF.

Link to comment

Hi Etienne,

 

The context here certainly helps, and it sounds like a wonderful process and product creation overall.

 

The process you've outlined is similar to how I create files ready for laser cutting, where different Pen Colours (which for ease I also do Class Bindings) mean different processes or depths (Score Surface, Engrave Surface, Cut Surface, Double / Triple Pass Cut Surface, 10% Cut, 20% Cut, etc).

 

Screenshot2025-02-17at10_23_06am.png.45da29f3ccd6f3bf859b8dccd647eded.png

Example of a Laser Cut and Engraved Access Point 'Coathanger' Design - J.Russell 2024

 

I personally think you're riding the line between a fairly diverse Standard Operating Procedure and an Automated Task (be it Python / Vectorscript / Marionette).

The appeal of replacing or supplementing this series of tasks with an Automated Task is understandable, however I think you'll hit several barriers in niche situations in attempting to cover such a broad basis of possible designs / arrangements / objects.

 

Certainly never wanting to deter creativity though, let's break your actions into some smaller steps!

  1. Name Recognition
    • Although I don't fully understand this step there are so many possible recognitions available in script options that I'm sure this would be possible.
    • Individual Objects in Vectorworks can be named.
    • If you were working in a Symbol Basis they are named and can be recalled very easily. Ungrouping and further manipulation can also occur.
    • Objects could have records attached and then be named and categorised in this way.
       
  2. Width (and/or Height & Depth)
    • Again something that is done in so many different ways in Vectorworks.
    • The most immediate is a concept called a 'Bounding Box' where the overall size of an object is measured and compared. You'll find this term in all the script options available to you.
    • Once you have a Bounding Box of all your items you'd be able to compare this to your fabric rolls (which could be a populated list stored in the script or from CSV).
       
  3. Ungrouping and Collision Checks
    • There's several methods of checking if a 2D Object is inside / touching another 2D Object, for example;
      • GetPolyPt & PtInPoly are both used in scripting to assess points.
      • Intersecting two objects will tell you if they overlap (and the result of this would be used as an indicator of overlap).
         
  4. Decomposition
    • Totally possible via scripts, you'd just need to ensure it's decomposed to exactly the level / detail you wanted.
       
  5. Classing by Colours and Rules
    • This is all just Criteria (defining things) and Classification (assigning things).
    • Any of the rules you wish to choose are fine, you'll just have to find the preferential order of things.
       
  6. Collinear Lines (Touch, Overlap or Superimposed)
    • We've covered this one - not in Marionette, and I'm still sure it's possible... probably.

All of the above IS possible.

I don't think you want a mega-script which just steamrolls from Step 1 to Step 6. 

I think you'd need to break each of the tasks down and create smaller scripts to optimise your workflow - as human interaction is still going to be both required and visually desired to ensure each step is working correctly.

 

Next Steps:

If you're really keen on learning Marionette then I think you should checkout the Vectorworks University, in particular the following courses;

If you're keen on learning either Vectorscript and/or Python then the resources directly related to Vectorworks are limited - only because, in particular Python, are so broadly applied.

 

I know it's not the immediate solve you might be looking for however if you persist it can and will lead to the best solution for you and your company long term.

Joining the forum however and asking questions is the first step - well done!

 

Cheers,

 

James

Link to comment
  • 2 months later...

Hello everyone,
I’ve made some progress toward my goal, but things aren’t perfect yet ^^
For now, I can detect colinear lines, but only the horizontal and vertical ones.
Also, in some cases, the network works fine, but in others, it forgets to process some black lines.
Could you please take a look?

I also forgot to mention that I would really like to turn the finished network into a Marionette command, but I'm still having trouble correctly identifying the objects to process using VSEL=TRUE or SEL=TRUE.
Thanks in advance!

MARIONETTE FILE COOLINEAR LINES.vwx

Link to comment

Join the conversation

You can post now and register later. If you have an account, sign in now to post with your account.
Note: Your post will require moderator approval before it will be visible.

Guest
Reply to this topic...

×   Pasted as rich text.   Restore formatting

  Only 75 emoji are allowed.

×   Your link has been automatically embedded.   Display as a link instead

×   Your previous content has been restored.   Clear editor

×   You cannot paste images directly. Upload or insert images from URL.

×
×
  • Create New...