How to rotate multiple bodies until they touch the edge of a third - SOLVED

Post here for help on using FreeCAD's graphical user interface (GUI).
Forum rules
and Helpful information
IMPORTANT: Please click here and read this first, before asking for help

Also, be nice to others! Read the FreeCAD code of conduct!
User avatar
luggw1
Posts: 89
Joined: Sun Feb 12, 2017 5:44 am
Location: Colorado
Contact:

How to rotate multiple bodies until they touch the edge of a third - SOLVED

Postby luggw1 » Sat Apr 18, 2020 5:22 pm

OS: Linux Mint 19.1
Word size of OS: 64-bit
Word size of FreeCAD: 64-bit
Version: 0.18.4.
Build type: Release
Python version: 3.6.8
Qt version: 5.9.5
Coin version: 4.0.0a
OCC version: 7.3.0
Locale: English/UnitedStates (en_US)

In the attached model, I'm modelling a small piece of the benchwork for my model railroad layout. The purpose is to model a bracket to hold a switch that will shut off track power on the lead to a drop-out section at a doorway. For orientation, the support and a section of the frame are on the right in the view that comes up when the file opens and the bridge with a support is on the left. The hinge is red.

My desire is to rotate the LeftHingeBody and BrigdeBody about a line passing through the axis of the hinge pin until some surface on the bottom of the bridge or bridge support just touches the lower right edge of the frame section. If I built the model correctly, it should be the right angled face of the bridge support that touches. FWIW, the bridge will not hang vertically if the model was built correctly. I frankly don't see how to do this in FreeCAD, but imagine it's simple enough to do.

If someone could provide some guidance in how to achieve this feat, I would be most appreciative.

Thanks
Bill Lugg
Attachments
SwitchBrackets-HingeEnd.FCStd
(93.73 KiB) Downloaded 11 times
Last edited by luggw1 on Wed Apr 22, 2020 2:20 pm, edited 1 time in total.
User avatar
ppemawm
Posts: 662
Joined: Fri May 17, 2013 3:54 pm
Location: Manhattan New York

Re: How to rotate multiple bodies until they touch the edge of a third

Postby ppemawm » Sat Apr 18, 2020 6:57 pm

luggw1 wrote:
Sat Apr 18, 2020 5:22 pm
My desire is to rotate the LeftHingeBody and BrigdeBody about a line passing through the axis of the hinge pin until some surface on the bottom of the bridge or bridge support just touches the lower right edge of the frame section.

One way to do this is to place both bodies in a Part container so that they can move together using the Part > Placement properties as shown below:

Capture.JPG
Capture.JPG (128.21 KiB) Viewed 204 times
.
You can obtain the center coordinates of the hinge axis by selecting an arc of the hinge then using this macro:

Code: Select all

print Gui.Selection.getSelectionEx()[0].SubObjects[0].Curve.Center

OS: Windows 10 (10.0)
Word size of OS: 64-bit
Word size of FreeCAD: 64-bit
Version: 0.19.20391 (Git)
Build type: Release
Branch: master
Hash: da92b8c242ead8cc106f480aa2eed0bac2edf10a
Python version: 3.6.8
Qt version: 5.12.1
Coin version: 4.0.0a
OCC version: 7.3.0
Locale: English/United States (en_US)
"It is a poor workman who blames his tools..." ;)
User avatar
luggw1
Posts: 89
Joined: Sun Feb 12, 2017 5:44 am
Location: Colorado
Contact:

Re: How to rotate multiple bodies until they touch the edge of a third

Postby luggw1 » Sat Apr 18, 2020 9:02 pm

ppemawm wrote:
Sat Apr 18, 2020 6:57 pm
You can obtain the center coordinates of the hinge axis by selecting an arc of the hinge then using this macro:

Code: Select all

print Gui.Selection.getSelectionEx()[0].SubObjects[0].Curve.Center
I attempted to use the macro and got the following syntax error:

Code: Select all

'SyntaxError'>: ('invalid syntax', ('/home/luggw1/.FreeCAD/FindCenter.FCMacro', 1, 9, 'print Gui.Selection.getSelectionEx()[0].SubObjects[0].Curve.Center\n'))
Never having used macros before I'm not sure how to interpret this message other that to say that it didn't work.

Also, how does one access the dialog shown in your snapshot. I'm having trouble finding it.

Thanks
Bill Lugg
User avatar
ppemawm
Posts: 662
Joined: Fri May 17, 2013 3:54 pm
Location: Manhattan New York

Re: How to rotate multiple bodies until they touch the edge of a third

Postby ppemawm » Sat Apr 18, 2020 9:52 pm

luggw1 wrote:
Sat Apr 18, 2020 9:02 pm
I attempted to use the macro and got the following syntax error:
I am not a programmer so hopefully someone else can help out with the syntax error.
In the meantime, try this one:

Code: Select all

__Name__ = 'Measure Circle'
__Comment__ = 'Compute the radius of a circle by 3 points or a circular edge'
__Author__ = 'peepsalot, galou_breizh'
__Version__ = '0.10.0'
__Date__ = '2019-02-19'
__License__ = 'LGPL-2.0-or-later'
__Web__ = 'http://www.freecadweb.org/wiki/Macro_MeasureCircle'
__Wiki__ = 'http://www.freecadweb.org/wiki/Macro_MeasureCircle'
__Icon__ = 'MeasureCircle.svg'
__Help__ = 'Make a selection of 3 points or an edge and launch, or launch first'
__Status__ = 'Beta'
__Requires__ = 'FreeCAD >= 0.18'
__Communication__ = ''
__Files__ = 'MeasureCircle.png'

import FreeCAD as app
import FreeCADGui as gui
import Part


def get_global_placement(obj):
    try:
        # If obj is part of a Part or Body.
        return obj.getParentGeoFeatureGroup().getGlobalPlacement()
    except AttributeError:
        return app.Placement()


class MeasureCircle:
    """Report the radius and center of a circle

    This class will report the computed radius and center of a circle given 3
    vertices or a circular edge.

    Just select the vertices and the result will be shown in the Report View.
    Edges may also be selected and count as two vertices.
    A circular edge can also be selected.
    If two edges are selected the end vertex of the second edge is not
    used in the calculation.
    """
    def __init__(self):
        self.points = []
        self.curve = None
        self.observer_needed = False
        self.get_elements_from_selection_ex()
        # We add the observer only if necessary.
        self.observer_needed = (self.curve is None)
        if self.observer_needed:
            gui.Selection.addObserver(self)
            app.Console.PrintMessage(
                'Select {} vertices on a circle\n'.format(
                    3 - len(self.points)))

    def addSelection(self, doc, obj, sub, pos):
        """Callback of the selection observer

        Do not rename.
        """
        o = app.getDocument(doc).getObject(obj)
        # Get the shape of selected object, if any.
        try:
            shape = o.Shape
        except AttributeError:
            app.Console.PrintMessage('Object is not a shape\n')
            return
        # Get the selected subshape.
        try:
            subshape = getattr(shape, sub)
        except:
            app.Console.PrintMessage(
                '"{}" is not a subshape of "{}"\n'.format(sub, shape))
            return
        if subshape.ShapeType == 'Vertex':
            self.add_point(o, subshape)
        elif subshape.ShapeType == 'Edge':
            self.on_edge(o, subshape)
        # Exit if we have enough points.
        if len(self.points) >= 3:
            self.on_three_points()

    def get_elements_from_selection_ex(self):
        for sel_object in gui.Selection.getSelectionEx():
            obj = sel_object.Object
            for subobject in sel_object.SubObjects:
                if type(subobject) == Part.Vertex:
                    self.add_point(obj, subobject)
                elif type(subobject) == Part.Edge:
                    self.on_edge(obj, subobject)
                # Exit if we have enough points.
                if len(self.points) >= 3:
                    self.on_three_points()
                    return

    def add_point(self, obj, v):
        """Add a point at the location of the selected vertex

        obj is the object the vertex belongs to. If obj belongs to a body, the
        body placement must be taken into account.
        """
        placement = get_global_placement(obj)
        point = placement.multVec(v.Point)
        if point in self.points:
            # Don't allow duplicate points.
            app.Console.PrintWarning('Point already chosen, ignoring\n')
            return
        self.points.append(point)

    def on_edge(self, obj, edge):
        """Add either two points or a circle

        obj is the object the edge belongs to. If obj belongs to a body, the
        body placement must be taken into account.
        """
        curve_type = type(edge.Curve)
        if curve_type == Part.Circle:
            self.on_circle(obj, edge)
        elif curve_type == Part.LineSegment:
            self.add_point(obj, edge.Vertexes[0])
            self.add_point(obj, edge.Vertexes[1])

    def finish(self):
        if self.curve:
            c = self.curve
            # line = Part.makeLine(c.Center, c.Center + c.XAxis * c.Radius)
            # obj = app.ActiveDocument.addObject('Part::Feature', 'Radius')
            # obj.Shape = line
            app.Console.PrintMessage('Diameter: {} mm\n'.format(2 * c.Radius))
            app.Console.PrintMessage('Radius: {} mm\n'.format(c.Radius))
            app.Console.PrintMessage(
                'Center: (X, Y, Z) = ({}, {}, {})\n'.format(
                    *list(c.Location)))
        if self.observer_needed:
            gui.Selection.removeObserver(self)

    def on_circle(self, obj, edge):
        """Add a circle and finish

        obj is the object the curve belongs to. If obj belongs to a body, the
        body placement must be taken into account.
        """
        placement = get_global_placement(obj)
        edge = edge.copy()
        edge.Placement = edge.Placement.multiply(placement)
        self.curve = edge.Curve
        self.finish()

    def on_three_points(self):
        v1 = self.points[0]
        v2 = self.points[1]
        v3 = self.points[2]
        self.curve = Part.Arc(v1, v2, v3).toShape().Curve
        self.finish()

if __name__ == '__main__':
    MeasureCircle()
luggw1 wrote:
Sat Apr 18, 2020 9:02 pm
how does one access the dialog shown in your snapshot.
Select Part which contains the bodies. Select the Placement value field then the button with the ellipsis in the Property panel to expand the panel:

Picture1.png
Picture1.png (202.57 KiB) Viewed 179 times
"It is a poor workman who blames his tools..." ;)
User avatar
easyw-fc
Posts: 2851
Joined: Thu Jul 09, 2015 9:34 am

Re: How to rotate multiple bodies until they touch the edge of a third

Postby easyw-fc » Sat Apr 18, 2020 10:16 pm

luggw1 wrote:
Sat Apr 18, 2020 5:22 pm
My desire is to rotate the LeftHingeBody and BrigdeBody about a line passing through the axis of the hinge pin until some surface on the bottom of the bridge or bridge support just touches the lower right edge of the frame section. If I built the model correctly, it should be the right angled face of the bridge support that touches. FWIW, the bridge will not hang vertically if the model was built correctly. I frankly don't see how to do this in FreeCAD, but imagine it's simple enough to do.
After having placed the two shapes inside a Part container, you can use Mover from Manipulator WB
mover.gif
mover.gif (339.5 KiB) Viewed 174 times
TheMarkster
Posts: 1566
Joined: Thu Apr 05, 2018 1:53 am

Re: How to rotate multiple bodies until they touch the edge of a third

Postby TheMarkster » Sat Apr 18, 2020 10:31 pm

luggw1 wrote:
Sat Apr 18, 2020 9:02 pm

Code: Select all

print Gui.Selection.getSelectionEx()[0].SubObjects[0].Curve.Center
I think you need to enclose the print parameters inside parentheses as of python version 3.

Try this instead:

Code: Select all

print(Gui.Selection.getSelectionEx()[0].SubObjects[0].Curve.Center)
My FreeCAD video series on youtube: https://www.youtube.com/c/mwganson
User avatar
luggw1
Posts: 89
Joined: Sun Feb 12, 2017 5:44 am
Location: Colorado
Contact:

Re: How to rotate multiple bodies until they touch the edge of a third

Postby luggw1 » Wed Apr 22, 2020 2:20 pm

Thanks for all the help. These things did exactly what I was looking for.

Bill Lugg