This is a migrated thread and some comments may be shown as answers.

Replace RadDiagramConnection in the RadDiagram

6 Answers 323 Views
Diagram
This is a migrated thread and some comments may be shown as answers.
Valentin
Top achievements
Rank 2
Iron
Iron
Iron
Valentin asked on 12 Apr 2018, 01:37 PM

Hello Telerik,

 

I'm working with a RadDiagram.

In my case, I have a red rectangle to show to user the limit of the diagram. If he moves a Shape outside of the red rectangle body, we replace the shape inside the rectangle (with an algorithm).

For all shape types, is working find, but not for RadDiagramConnection.

 

My sub :

Private Sub MoveShape(p_shape As RadDiagramItem)
    If (p_shape Is Nothing) Then Exit Sub
 
    If Me._moveShapeCount >= 8 Then 'Used to fix a bug with infinite loop (StackOverFlowException) !
        Me._moveShapeCount = 0
        Exit Sub
    End If
 
    Try
        'Memory
        Dim shapeAsRectangle As Rect = p_shape.GetActualBounds() 'Used to have the good values when shape is rotated
        Dim isRectangleRotated As Boolean = False
        Dim isShapePositionModified As Boolean = False
 
        'Rotation management
        If TryCast(p_shape, RadDiagramShape) IsNot Nothing Then
            'Image / Elipse
            isRectangleRotated = (Not ListMissOutAngles.Exists(Function(a) a = DirectCast(p_shape, RadDiagramShape).RotationAngle))
        ElseIf TryCast(p_shape, RadDiagramConnection) IsNot Nothing Then
            'Me.ReplaceConnectorShape(p_shape) 'Specific treatment because Connection not has rotation angle and can have 2 points inside the line
            'Exit Sub
        ElseIf TryCast(p_shape, RadDiagramTextShape) IsNot Nothing Then
            'Boite de texte
            isRectangleRotated = (Not ListMissOutAngles.Exists(Function(a) a = DirectCast(p_shape, RadDiagramTextShape).RotationAngle))
        Else
            'Kc / Gap / Ref / Calculation / Adiru / FSI
            isRectangleRotated = (Not ListMissOutAngles.Exists(Function(a) a = DirectCast(p_shape, RadDiagramShapeBase).RotationAngle))
        End If
 
        'Width management
        If p_shape.Bounds.Width < (MinX + Me.BoundariesWidth) Then 'Manage cases only if shape width is < to red rectangle width (infinite loop risk)
            If shapeAsRectangle.Left < MinX Then
                If isRectangleRotated Then
                    p_shape.Position = New Point((p_shape.Bounds.X + (MinX - shapeAsRectangle.Left)), p_shape.Bounds.Y)
                Else
                    p_shape.Position = New Point((MinX + 2), p_shape.Bounds.Y)
                End If
 
                isShapePositionModified = True
            End If
 
            If shapeAsRectangle.Right > (MinX + BoundariesWidth) Then
                p_shape.Position = New Point((p_shape.Bounds.X + ((Me.BoundariesWidth + MinX) - shapeAsRectangle.Right)), p_shape.Bounds.Y)
                isShapePositionModified = True
            End If
        Else
            Exit Sub
        End If
 
        'Height management
        If p_shape.Bounds.Height < (MinY + BoundariesHeight) Then 'Manage cases only if shape height is < to red rectangle height (infinite loop risk)
            If shapeAsRectangle.Top < MinY Then
                If isRectangleRotated Then
                    p_shape.Position = New Point(p_shape.Bounds.X, (p_shape.Bounds.Y + (MinY - shapeAsRectangle.Top)))
                Else
                    p_shape.Position = New Point(p_shape.Bounds.X, (MinY + 2))
                End If
 
                isShapePositionModified = True
            End If
 
            If shapeAsRectangle.Bottom > (MinY + BoundariesHeight) Then
                If isRectangleRotated Then
                    p_shape.Position = New Point(p_shape.Bounds.X, (p_shape.Bounds.Top - (shapeAsRectangle.Bottom - BoundariesHeight) + MinY))
                Else
                    p_shape.Position = New Point(p_shape.Bounds.X, (p_shape.Bounds.Y - (p_shape.Bounds.Bottom - (MinY + BoundariesHeight)) - 2))
                End If
 
                isShapePositionModified = True
            End If
        Else
            Exit Sub
        End If
 
        If isShapePositionModified Then
            Me._moveShapeCount += 1
            Me.MoveShape(p_shape)
        End If
    Catch ex As Exception
        If Debugger.IsAttached Then Debugger.Break()
        MAATrace.Log("MoveShape EXCEPTION", "Error in MoveShape() (top-left position : '" + p_shape.Position.ToString() + "') : " + ex.Message)
    End Try
End Sub

 

For example, consider the first case => If shapeAsRectangle.Left < MinX

For all shapes, the p_shape.Position is set to 22, but for RadDiagramConnection, the value is not updated.

 

Do you know why the position is not updated for RadDiagramConnection ? And how can I resolve it ?

Furthermore, I should to be able to know if there is a rotation for the shape which encircle the RadDiagramConnection (the If, elseif, elseif... is a draft copy)

 

Thanks a lot.

6 Answers, 1 is accepted

Sort by
0
Petar Mladenov
Telerik team
answered on 16 Apr 2018, 07:44 AM
Hi Valentin,

Position property comes from the RadDiagramItem class which is base class for RadDiagramShape and RadDiagramConnection. However, it's main purpose is to position shapes and could be successfully used 2-way to get and set (control) the top left point of the shape bounds. In RadDiagramConnection it could be used only as a getter - returns the top left point of the connection's bounding rectangle. For more precise calculations , connections provide:

- StartPoint and EndPoint properties of type Point - 
        - ConnectionPoints property of type IList<Point> - collection of all intermediate points

For polyline connection, it's easy to detect when connection is outside of rectangle - you just check the start, end and the intermediate points. For more complex situations we encourage you to check the math functions in Telerik.Windows.Diagrams.Core.Utils class. Methods like InterectPointOnEllipse or AreLinesIntersecting (and many more) could give you the results you need.
        

Regards,
Petar Mladenov
Progress Telerik
Want to extend the target reach of your WPF applications, leveraging iOS, Android, and UWP? Try UI for Xamarin, a suite of polished and feature-rich components for the Xamarin framework, which allow you to write beautiful native mobile apps using a single shared C# codebase.
0
Valentin
Top achievements
Rank 2
Iron
Iron
Iron
answered on 16 Apr 2018, 09:04 AM

Hi Petar,

 

Before to test the replacement for the Connection when set it's position, I tried to write an algorithm to manage the 2 or 4 points inside the Connection shape, but I faced to a complex cases for curved connections... (like you said, polyline it's easy)

And I saw that the list can have a lot of points, and it is very difficult. I don't know how I can manage all of cases !

 

I don't know if you have a search pist or other ? May be we can find the border rectangle of the Connection, and calculate the offset to move all of points ?

 

Thank you.

0
Petar Mladenov
Telerik team
answered on 19 Apr 2018, 06:55 AM
Hello Valentin,

Bezier connection is generally described by 4 points and a tension parameter. Below I will paste a method which can give an approximate list of points describing the bezier curve:

var bezierPoints = new[] { connection.StartPoint, Utils.Lerp(connection.StartPoint, connection.ConnectionPoints[0], connection.BezierTension), Utils.Lerp(connection.EndPoint, connection.ConnectionPoints[1], connection.BezierTension), connection.EndPoint };
 
var approximatedBezierPoints = Utils.ApproximateBezierCurve(bezierPoints, 30);

I hope it can serve well in your scenario.

For bounding rectangle of a polyline, I guess this s a math problem well described in some math forums or stackoverflow, wolfram alpha etc. I guess it is a matter of finding the 4 Maximum points for North, West, East and South.

Regards,
Petar Mladenov
Progress Telerik
Want to extend the target reach of your WPF applications, leveraging iOS, Android, and UWP? Try UI for Xamarin, a suite of polished and feature-rich components for the Xamarin framework, which allow you to write beautiful native mobile apps using a single shared C# codebase.
0
Valentin
Top achievements
Rank 2
Iron
Iron
Iron
answered on 19 Apr 2018, 10:13 AM

Hi Petar,

 

I choose antoher way : I found the border rectangle of the connector (with X,Y, Left, Right... values).

I calculated the offset depanding on my work area, and I apply this offset to all points (Start, End, and all of the ConnectionPoints).

In the debugger, it's working (values and the list are updated), but visually, points are moved, but not the stroke.

 

See my code :

If connectorAsRectangle.X < MinX Then
    diffOut = (MinX - connector.StartPoint.X) 'Consider that the start point is the extrem left point
    connector.StartPoint = New Point(connector.StartPoint.X + diffOut, connector.StartPoint.Y)
    connector.EndPoint = New Point(connector.EndPoint.X + diffOut, connector.EndPoint.Y)
 
    For idxPts As Integer = 0 To (connector.ConnectionPoints.Count - 1) 'I chosse a For loop because Foreach loop not updated the points
        Dim cPoint As Point = connector.ConnectionPoints(idxPts)
        cPoint.X = (cPoint.X + diffOut)
        connector.ConnectionPoints(idxPts) = cPoint
    Next
End If

 

I attached a screenshot : this is when I clicked on my connector, after the move.

Do you know what is the problem ?

 

Thank you !

0
Valentin
Top achievements
Rank 2
Iron
Iron
Iron
answered on 19 Apr 2018, 10:35 AM

Hi Petar,

Sorry for the previous question, but I found the solution.

To move the ConnectionPoints (values and visually), I done this :

For idxPts As Integer = 0 To (connector.ConnectionPoints.Count - 1)
    Dim cPoint As Point = connector.ConnectionPoints(idxPts)
    Dim ncPoint As New Point((cPoint.X + diffOut), cPoint.Y)
    connector.ConnectionPoints.Remove(cPoint)
    connector.InsertConnectionPoint(ncPoint, (idxPts))
Next

 

And the connector is correctly moved !

 

I'm going to do this algorythm for the 4 sides (Left, Top, Bottom, Right) to move the connector.

0
Valentin
Top achievements
Rank 2
Iron
Iron
Iron
answered on 19 Apr 2018, 01:02 PM

Hi,

I found a solution it's working find and for the 3 connector types.

Private Sub ReplaceConnectorShape(p_shape As RadDiagramItem)
    If (p_shape Is Nothing) Then Exit Sub
 
    Try
        Dim connector As RadDiagramConnection = DirectCast(p_shape, RadDiagramConnection)
        Dim diffOut As Double = 0 'Difference between point (start or end) and the diagram red border
        Dim connectorAsRectangle As Rect = p_shape.GetActualBounds() 'Used to have the global rectangle around the connector
        Dim extremValue As Double = 0 'Furthest value on axis (X or Y)
 
        'No replace Connector if it is more big than red rectangle (width)
        If (connectorAsRectangle.Width > BoundariesWidth) OrElse ((connectorAsRectangle.Left < MinX) AndAlso (connectorAsRectangle.Right > (MinX + BoundariesWidth))) Then Exit Sub
 
        'No replace Connector if it is more big than red rectangle (height)
        If (connectorAsRectangle.Height > BoundariesHeight) OrElse ((connectorAsRectangle.Top < MinY) AndAlso (connectorAsRectangle.Bottom > (MinY + BoundariesHeight))) Then Exit Sub
 
        'Left
        If connectorAsRectangle.X < MinX Then
            extremValue = Me.GetExtremPointForConnectorBySide(connector, 1)
            diffOut = (MinX - extremValue)
            connector.StartPoint = New Point(connector.StartPoint.X + diffOut, connector.StartPoint.Y)
            connector.EndPoint = New Point(connector.EndPoint.X + diffOut, connector.EndPoint.Y)
 
            For idxPts As Integer = 0 To (connector.ConnectionPoints.Count - 1)
                Dim cPoint As Point = connector.ConnectionPoints(idxPts)
                Dim ncPoint As New Point((cPoint.X + diffOut), cPoint.Y)
                connector.ConnectionPoints.Remove(cPoint)
                connector.InsertConnectionPoint(ncPoint, (idxPts))
            Next
        End If
 
        'Top
        If connectorAsRectangle.Y < MinY Then
            extremValue = Me.GetExtremPointForConnectorBySide(connector, 2)
            diffOut = (MinY - extremValue)
            connector.StartPoint = New Point(connector.StartPoint.X, connector.StartPoint.Y + diffOut)
            connector.EndPoint = New Point(connector.EndPoint.X, connector.EndPoint.Y + diffOut)
 
            For idxPts As Integer = 0 To (connector.ConnectionPoints.Count - 1)
                Dim cPoint As Point = connector.ConnectionPoints(idxPts)
                Dim ncPoint As New Point(cPoint.X, (cPoint.Y + diffOut))
                connector.ConnectionPoints.Remove(cPoint)
                connector.InsertConnectionPoint(ncPoint, (idxPts))
            Next
        End If
 
        'Right
        If connectorAsRectangle.X + connectorAsRectangle.Width > (MinX + BoundariesWidth) Then
            extremValue = Me.GetExtremPointForConnectorBySide(connector, 3)
            diffOut = (extremValue - (MinX + BoundariesWidth))
            connector.StartPoint = New Point(connector.StartPoint.X - diffOut, connector.StartPoint.Y)
            connector.EndPoint = New Point(connector.EndPoint.X - diffOut, connector.EndPoint.Y)
 
            For idxPts As Integer = 0 To (connector.ConnectionPoints.Count - 1)
                Dim cPoint As Point = connector.ConnectionPoints(idxPts)
                Dim ncPoint As New Point((cPoint.X - diffOut), cPoint.Y)
                connector.ConnectionPoints.Remove(cPoint)
                connector.InsertConnectionPoint(ncPoint, (idxPts))
            Next
        End If
 
        'Bottom
        If connectorAsRectangle.Y + connectorAsRectangle.Height > (MinY + BoundariesHeight) Then
            extremValue = Me.GetExtremPointForConnectorBySide(connector, 4)
            diffOut = (extremValue - (MinY + BoundariesHeight))
            connector.StartPoint = New Point(connector.StartPoint.X, (connector.StartPoint.Y - diffOut))
            connector.EndPoint = New Point(connector.EndPoint.X, (connector.EndPoint.Y - diffOut))
 
            For idxPts As Integer = 0 To (connector.ConnectionPoints.Count - 1)
                Dim cPoint As Point = connector.ConnectionPoints(idxPts)
                Dim ncPoint As New Point(cPoint.X, (cPoint.Y - diffOut))
                connector.ConnectionPoints.Remove(cPoint)
                connector.InsertConnectionPoint(ncPoint, (idxPts))
            Next
        End If
    Catch ex As Exception
        Dim msgError As New MessageBox(MaaWpfControls.Localize.Translate("MirBuilder_ErrorMessage_Title"), "Error during connector replacement", MessageBox.IconExamples.EXCLAMATION)
        msgError.AddButton("OK", Windows.Media.Colors.Transparent, MessageBox.IconExamples.CLOSE)
        msgError.DisplayAsync(Me.InspectionReportTemplate.Parent)
    End Try
End Sub
 
Private Function GetExtremPointForConnectorBySide(p_connector As RadDiagramConnection, p_side As Integer) As Double
    Dim extremValue As Double = 0
 
    Select Case p_side
        Case 1 'Left
            extremValue = MinX
 
            If p_connector.StartPoint.X < extremValue Then extremValue = p_connector.StartPoint.X
            If p_connector.EndPoint.X < extremValue Then extremValue = p_connector.EndPoint.X
 
            For Each cPoint As Point In p_connector.ConnectionPoints
                If cPoint.X < extremValue Then extremValue = cPoint.X
            Next
        Case 2 'Top
            extremValue = MinY
 
            If p_connector.StartPoint.Y < extremValue Then extremValue = p_connector.StartPoint.Y
            If p_connector.EndPoint.Y < extremValue Then extremValue = p_connector.EndPoint.Y
 
            For Each cPoint As Point In p_connector.ConnectionPoints
                If cPoint.Y < extremValue Then extremValue = cPoint.Y
            Next
        Case 3 'Right
            extremValue = (MinX + BoundariesWidth)
 
            If p_connector.StartPoint.X > extremValue Then extremValue = p_connector.StartPoint.X
            If p_connector.EndPoint.X > extremValue Then extremValue = p_connector.EndPoint.X
 
            For Each cPoint As Point In p_connector.ConnectionPoints
                If cPoint.X > extremValue Then extremValue = cPoint.X
            Next
        Case 4 'Bottom
            extremValue = (MinY + BoundariesHeight)
 
            If p_connector.StartPoint.Y > extremValue Then extremValue = p_connector.StartPoint.Y
            If p_connector.EndPoint.Y > extremValue Then extremValue = p_connector.EndPoint.Y
 
            For Each cPoint As Point In p_connector.ConnectionPoints
                If cPoint.Y > extremValue Then extremValue = cPoint.Y
            Next
    End Select
 
    Return extremValue
End Function

 

 

 

 

 

 I hope this help !

Tags
Diagram
Asked by
Valentin
Top achievements
Rank 2
Iron
Iron
Iron
Answers by
Petar Mladenov
Telerik team
Valentin
Top achievements
Rank 2
Iron
Iron
Iron
Share this question
or