News:

BB code in posts seems to be working again!
I haven't turned on every single tag, so please let me know if there are any that are used/needed but not activated.

Main Menu

Find simple lines and rectangles in a drawing

Started by Yacine, October 26, 2024, 10:33:11 AM

Previous topic - Next topic

0 Members and 1 Guest are viewing this topic.

Yacine

Hi guys,
if you ever need to analyze a Visio drawing and want to find out what the shapes are, you can of course check their masters. But how do you identify simple lines or rectangles reliably? Here are two neat snippets that might help because there are quite a few conditions to check.
For simple lines, you want to look for:
  • It must be a 1D shape.
  • No sub-shapes (not a group).
  • Only one Geometry section.
  • Exactly two rows in the Geometry:
    MoveTo and
    LineTo.
  • No master shape.
And for simple rectangles:
  • The shape must not be 1D.
  • No sub-shapes.
  • Only one Geometry section.
  • Five rows in the Geometry:
    MoveTo, followed by four
    LineTo rows.
  • No master shape.


' VBA function to check if a shape is a simple rectangle
Function IsSimpleRectangle(shp As Visio.Shape) As Boolean
    On Error GoTo ErrorHandler
   
    ' Condition 1: OneD must be set to False
    If shp.OneD Then
        ' Debug.Print "Shape is OneD"
        IsSimpleRectangle = False
        Exit Function
    End If
   
    ' Condition 2: No sub-shapes (not a group)
    If shp.Shapes.Count <> 0 Then
        ' Debug.Print "Shape has sub-shapes"
        IsSimpleRectangle = False
        Exit Function
    End If
   
    ' Condition 3: Only one Geometry section must exist
    If shp.SectionExists(Visio.VisSectionIndices.visSectionFirstComponent + 1, Visio.VisExistsFlags.visExistsLocally) Then
        ' Debug.Print "Shape has several geometry sections"
        IsSimpleRectangle = False
        Exit Function
    End If
   
    ' Condition 4: There must be exactly 5 rows in the Geometry section
    If shp.RowCount(Visio.VisSectionIndices.visSectionFirstComponent) <> 6 Then
        ' Debug.Print "Geometry section does not have exactly 5 rows"
        IsSimpleRectangle = False
        Exit Function
    End If
   
    ' Condition 5: The rows must follow the correct pattern: MoveTo, LineTo, LineTo, LineTo, LineTo
    If Not ((shp.RowType(Visio.VisSectionIndices.visSectionFirstComponent, 1) = Visio.VisRowTags.visTagMoveTo Or _
            shp.RowType(Visio.VisSectionIndices.visSectionFirstComponent, 1) = Visio.VisRowTags.visTagRelMoveTo) And _
            (shp.RowType(Visio.VisSectionIndices.visSectionFirstComponent, 2) = Visio.VisRowTags.visTagLineTo Or _
            shp.RowType(Visio.VisSectionIndices.visSectionFirstComponent, 2) = Visio.VisRowTags.visTagRelLineTo) And _
            (shp.RowType(Visio.VisSectionIndices.visSectionFirstComponent, 3) = Visio.VisRowTags.visTagLineTo Or _
            shp.RowType(Visio.VisSectionIndices.visSectionFirstComponent, 3) = Visio.VisRowTags.visTagRelLineTo) And _
            (shp.RowType(Visio.VisSectionIndices.visSectionFirstComponent, 4) = Visio.VisRowTags.visTagLineTo Or _
            shp.RowType(Visio.VisSectionIndices.visSectionFirstComponent, 4) = Visio.VisRowTags.visTagRelLineTo) And _
            (shp.RowType(Visio.VisSectionIndices.visSectionFirstComponent, 5) = Visio.VisRowTags.visTagLineTo Or _
            shp.RowType(Visio.VisSectionIndices.visSectionFirstComponent, 5) = Visio.VisRowTags.visTagRelLineTo)) Then
        ' Debug.Print "Rows in geometry section don't match expected MoveTo and LineTo sequence"
        IsSimpleRectangle = False
        Exit Function
    End If
   
    ' Condition 6: It must not have a master.
    If Not shp.Master Is Nothing Then
        ' Debug.Print "Shape has a master"
        IsSimpleRectangle = False
        Exit Function
    End If
   
    ' If all conditions are met, it is a simple rectangle
    ' Debug.Print "Success: Simple rectangle found"
    IsSimpleRectangle = True
    Exit Function
   
ErrorHandler:
    ' Debug.Print "Error during check: " & Err.Description
    IsSimpleRectangle = False
End Function




' VBA function to check if a shape is a simple line
Function IsSimpleLine(shp As Visio.Shape) As Boolean
    On Error GoTo ErrorHandler
   
    ' Condition 1: OneD must be set to True
    If Not shp.OneD Then
        ' Debug.Print "Shape is not OneD"
        IsSimpleLine = False
        Exit Function
    End If
   
    ' Condition 2: No sub-shapes (not a group)
    If shp.Shapes.Count <> 0 Then
        ' Debug.Print "Shape has sub-shapes"
        IsSimpleLine = False
        Exit Function
    End If
   
    ' Condition 3: Only one Geometry section must exist
    If shp.SectionExists(Visio.VisSectionIndices.visSectionFirstComponent + 1, Visio.VisExistsFlags.visExistsLocally) Then
        ' Debug.Print "Shape has several geometry sections"
        IsSimpleLine = False
        Exit Function
    End If
   
    ' Condition 4: There must be exactly 3 rows in the Geometry section (MoveTo and LineTo)
    If shp.RowCount(Visio.VisSectionIndices.visSectionFirstComponent) <> 3 Then
        ' Debug.Print "Geometry section does not have exactly 3 rows"
        IsSimpleLine = False
        Exit Function
    End If
   
    ' Condition 5: The first row must be MoveTo and the second row must be LineTo
    If Not ((shp.RowType(Visio.VisSectionIndices.visSectionFirstComponent, 1) = Visio.VisRowTags.visTagMoveTo Or _
            shp.RowType(Visio.VisSectionIndices.visSectionFirstComponent, 1) = Visio.VisRowTags.visTagRelMoveTo) And _
            (shp.RowType(Visio.VisSectionIndices.visSectionFirstComponent, 2) = Visio.VisRowTags.visTagLineTo Or _
            shp.RowType(Visio.VisSectionIndices.visSectionFirstComponent, 2) = Visio.VisRowTags.visTagRelLineTo)) Then
        ' Debug.Print "Rows in geometry section don't match expected MoveTo and LineTo sequence"
        IsSimpleLine = False
        Exit Function
    End If
   
    ' Condition 6: It must not have a master.
    If Not shp.Master Is Nothing Then
        ' Debug.Print "Shape has a master"
        IsSimpleLine = False
        Exit Function
    End If
   
    ' If all conditions are met, it is a simple line
    ' Debug.Print "Success: Simple line found"
    IsSimpleLine = True
    Exit Function
ErrorHandler:
    ' Debug.Print "Error during check: " & Err.Description
    IsSimpleLine = False
End Function


Hopefully, these snippets save someone out there some debugging hours in the future. 😊 Feel free to adapt them to suit your specific needs!
Yacine

Surrogate

#1
Hi, Yacine! Great job!
Quote from: Yacine on October 26, 2024, 10:33:11 AMFor simple lines, you want to look for:
In last year I try creating master-shahe (or group shape) analizer, but I used more simple criterias.
What is the purpose of your attempted analysis?

Yacine

#2
Quote from: Surrogate on October 27, 2024, 07:44:19 PMWhat is the purpose of your attempted analysis?

That is indeed a very exciting project. I've been tasked to generate HMI mockups from my P&IDs.
I our current workflow our programmers redraw my P&IDs in Siemens' Tia Portal to create HMI GUIs.
This is cumbersome and pity since the job has already be done.

In this automation task I generate a report of all the actors and sensors, with their positions and orientations, metadata from the P&ID itself and additional prop data for the configuration of the items in the HMI.

Additionally I provide details of purely graphical items, such as simple text shapes, lines and connectors.


As for the graphics themselves here are my results so far.
Source:
Unbenannt.PNG
Result:
Unbenannt2.PNG
Yacine

Yacine

Here's for example the function to retrieve the vertices of a connector. It returns them both in local and global coordinates, as I don't know yet how tia portal will you use the data.

def get_connector_vertices(shape):
    """
    Funktion, um die Eckpunkte eines Visio-Connektors auszulesen.
    Gibt sowohl lokale als auch globale Koordinaten der Punkte zurück.
   
    :param shape: Visio-Shape-Objekt, das ein Connektor ist.
    :return: Tuple mit zwei Strings: lokale und globale Koordinaten als doppelt separierter String [(local_x, local_y), ...] und [(global_x, global_y), ...]
    """
    if shape.OneD != -1:
        raise ValueError("Das angegebene Shape ist kein Connektor.")
   
    loc_points = []
    glob_points = []
    section_index = c.visSectionFirstComponent  # Zugriff auf die erste Geometriesektion
    row_count = shape.RowCount(section_index)
   
    for row in range(row_count):
        if shape.CellsSRCExists(section_index, row, c.visX, False):
            # Lokale Koordinaten auslesen
            local_x = round(shape.CellsSRC(section_index, row, c.visX).Result('mm'), 2)
            local_y = round(shape.CellsSRC(section_index, row, c.visY).Result('mm'), 2)
           
            # Globale Koordinaten berechnen
            pin_x = shape.Cells("PinX").Result("mm")
            pin_y = shape.Cells("PinY").Result("mm")
            global_x = round(pin_x + local_x, 2)
            global_y = round(pin_y + local_y, 2)
           
            # Hinzufügen zur Liste der Punkte
            loc_points.append(f'{local_x},{local_y}')
            glob_points.append(f'{global_x},{global_y}')
   
    loc_points = ';'.join(loc_points)
    glob_points = ';'.join(glob_points)       
    return loc_points, glob_points
Yacine

Surrogate

Quote from: Yacine on October 28, 2024, 08:26:03 AMIt returns them both in local and global coordinates
For global (a.k.a. absolute) coordinates you can use XYToPage method. My article about usage of this method you can find there
Quote from: Yacine on October 28, 2024, 08:17:11 AMThat is indeed a very exciting project.
I had a similar project too.

Yacine

Pity that russian is not so sexy, but it would definitely be more useful than italian ;)
Good job.
Yacine

Surrogate

#6
Quote from: Yacine on October 28, 2024, 09:07:43 AMGood job.
I didn't participate in that freelance project for long. I didn't work well with the architect. it was her who came up with the idea of replacing the shapes with "more beautiful" ones (as at right part of screenshot). I don't relate for that beauty....

The main goals of our client were overshadowed. The criteria for finding "replacement shapes" were very strange (look at Interim conclusions). I was self-effacing and simply waited for the contract to expire. My cool story


Browser ID: smf (possibly_robot)
Templates: 4: index (default), Display (default), GenericControls (default), GenericControls (default).
Sub templates: 6: init, html_above, body_above, main, body_below, html_below.
Language files: 4: index+Modifications.english (default), Post.english (default), Editor.english (default), Drafts.english (default).
Style sheets: 4: index.css, attachments.css, jquery.sceditor.css, responsive.css.
Hooks called: 321 (show)
Files included: 32 - 1207KB. (show)
Memory used: 1178KB.
Tokens: post-login.
Cache hits: 15: 0.00221s for 26,750 bytes (show)
Cache misses: 4: (show)
Queries used: 16.

[Show Queries]