Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Is it possible to read a virtual constraint's "distance" property? #52

Closed
ceremcem opened this issue Sep 3, 2018 · 38 comments
Closed

Comments

@ceremcem
Copy link
Collaborator

ceremcem commented Sep 3, 2018

By saying "virtual constraint", I meant a constraint which is disabled so has no effect the model.

If we could create a virtual constraint and read its data as if any other object within the Spreadsheet, it would be possible to create dynamically calculated dimensions: https://forum.freecadweb.org/viewtopic.php?f=3&t=30676

Is it possible to read - i.e. - distance property of a disable constraint:

virtual-constraint

@realthunder
Copy link
Owner

This possible, and actually not that difficult to do. I am just not sure whether assembly WB is the right place to provide this feature. Let me think about it.

@ceremcem
Copy link
Collaborator Author

ceremcem commented Sep 3, 2018

Thinking again, currently I can not imagine any useful cases that would require using values other than diff_x, diff_y and diff_z. So I thought we might

  1. Put 2 draft points
  2. Anchor them our desired points with PointsCoincident
  3. Calculate Point001.X - Point002.X and use it as a length of box.

This approach also seems

  1. Practical
  2. Declarative

It's almost done, but the problem is that the coordinates of points does not change when I move the bound part:

coordinate does not change

Note: I can't use sub-shape binder here, it throws Cyclic Dependency exception. If this is not normal, I can create an issue for that. Binder can be created if faces are selected, instead of the whole cube.

@ceremcem
Copy link
Collaborator Author

ceremcem commented Sep 3, 2018

Oh, wait, wait, it's Point001.Placement.Base.x

@ceremcem
Copy link
Collaborator Author

ceremcem commented Sep 3, 2018

No luck yet.

I expect the following code to output 46.59:

App.ActiveDocument.Point001.Placement.Base.x - App.ActiveDocument.Point.Placement.Base.x

in this model because Manipulator WB measures 46.59mm:

image

@realthunder
Copy link
Owner

Instead of using DraftPoint, you should use a DraftLine here. Simply constraint the two end point of the line to those two cubes. And you can read out the Length property of the line. asm3 has special handling of draft wire/circle/arc for 2D/3D sketching purpose. You Probably can use draft wire to constrain a 2D rectangle directly and extrude as the outer box in this simple case. For real life use case though, I would still recommend going the shape binder and normal sketch route. You can use a body, and shapebinder will then auto adjust its linking to avoid cyclic reference.

@ceremcem
Copy link
Collaborator Author

ceremcem commented Sep 4, 2018

DraftLine approach (limited success): box-with-draft-line.fcstd.remove-extension.zip

dynamic-measurement-success

While this seem to work as expected, we can not move the red cube in the other directions because the DraftLine should be and is also parallel to outer box edge.

Moreover, DraftLine creates undesired interference with movement of connected objects:

draft-line-breaks-freedom

@realthunder
Copy link
Owner

realthunder commented Sep 4, 2018

You should completely fix two box with constrains first (hint: if you don't want the box to rotate, use LockAngle in PlaneAlignment), then add the draft line. You can use constraints other than point coincidence, for example, to measure point to plane distance with perpendicular and point in plane.

@ceremcem
Copy link
Collaborator Author

ceremcem commented Sep 4, 2018

I will only continue this conversation if you have your word that you won't find me and shoot me in the head.

@realthunder
Copy link
Owner

Wait, what?

@ceremcem
Copy link
Collaborator Author

ceremcem commented Sep 4, 2018

I think I asked too many things already :)

@realthunder
Copy link
Owner

It's nice to have an active tester. Besides, the thing you are trying to do is really at the frontier in the world of FreeCAD. I think nobody yet has a clear idea of what's the best workflow in FC.

@ceremcem
Copy link
Collaborator Author

ceremcem commented Sep 4, 2018

Okay, I assume I got your word then :)

You should completely fix two box with constrains first, then add the draft line.

That would be an obvious resolution, but it seems it's not that practical because we have to explicitly declare all constraints for a design, which removes the freedom of "okay, you, box, stay where I put you".

You can use constraints other than point coincidence, for example, to measure point to plane distance with perpendicular and point in plane.

Yes, I thought about that too, but what if the objects will be rotated? Or objects have no plain faces?

All these experiments were for clarifying if "Asm3 is the right place to ask this or not" (from the point of view of myself) and led me to that point: This feature (which I want to call it "Assembly [Based] Dimensions") should be used in the following way (in the end):

  • Lets think there is a caliper tool (like in Manipulator WB) which will snap to vertices and center of circles.
  • We'll select two points (in real life we would take measurements between points)
  • This object will provide us distance, x, y and z which we can use it in the Spreadsheet and set some other things.

This operation should be that easy. Although a separate caliper tool and snapping to center are fancy features, I guess it would be both practical and doable by that "virtual constraints".

@realthunder
Copy link
Owner

That would be an obvious resolution, but it seems it's not that practical because we have to explicitly declare all constraints for a design, which removes the freedom of "okay, you, box, stay where I put you".

Yes, I thought about that too, but what if the objects will be rotated? Or objects have no plain faces?

The virtual constraint proposal will face the exact same problems above. As long as the part's movement is legal with the given constraints, it is perfectly normal for the next auto solve to change the part's placement and ruin your measurement.

I am investigating other possibilities, such as supporting shape distance calculation directly in expression, which may or may not be possible.

BTW, it is easy to snap a draft point/line on the center of any face. Simply use the PointCoincident constraint on that face and point, PointCoincident will use the center of the face as a point.

@realthunder
Copy link
Owner

With this commit, it is now possible to get distance and many more information directly from expression.

If the parts you want to measure are inside the same assembly, then the following expression measure two vertex from two boxes,

Box.Shape.Vertex1.Point.distanceToPoint(Box001.Shape.Vertex1.Point)

There is also distanceToLine/Plane(), etc. Anything exposed by Python through the property can be used in the expression.

If the Box are inside different assembly, the recommended way of doing it is to create Element to bring the geometry element into same assembly, and doing measurement on their Shape.

@ceremcem
Copy link
Collaborator Author

ceremcem commented Sep 14, 2018

A Mini Tutorial

As an example, I created two elements, labeled front and back which represents two parallel faces of a simple shape:

image

front = lambda: App.ActiveDocument.getObjectsByLabel('front')[0].Shape
back = lambda: App.ActiveDocument.getObjectsByLabel('back')[0].Shape

Goal

Measure the distance between them with distanceToPlane method, which is 6.50 mm at the moment.

Get the distance quickly

front().Vertexes[0].Point.distanceToPoint(back().Vertexes[0].Point) 
# => 6.5 (which seems what we wanted) 

front().Vertexes[0].Point.distanceToPoint(back().Vertexes[1].Point)
# => 17.45377259416224 (upps!)

# How do we know which vertices will give us the correct measurement?

Correct Way

It's obvious that we should measure the distance between a random point from one plane to the other plane itself (PointToPlane):

def get_plane(p1, p2, p3): 
    edge1 = p1 - p2 
    edge2 = p1 - p3 
    normal = edge1.cross(edge2)
    return (p1, normal)

def get_element_plane(shape):
    v = shape.Vertexes
    return get_plane(v[0].Point, v[1].Point, v[2].Point)

x1 = front().Vertexes[0].Point 
x2 = get_element_plane(back())

dist = x1.distanceToPlane(*x2)
# => 6.5 (exactly what we expected)

Conclusion

As we used two Elements in this example, we can dynamically measure the distance between any two entities (on the same object or any two distinct objects) and measurements will be still correct even after replacing an object with a totally different one.

Macro

Here is the macro that calculates the distance declared in a Spreadsheet: https://github.com/ceremcem/assembly-dimensions

Usage

  1. Write the following string in a cell in a spreadsheet:
#! distance from Element27 to Element36
  1. Run the macro
  2. Distance between Element27 and Element36 will be calculated and written into the next colum.

@realthunder
Copy link
Owner

realthunder commented Sep 15, 2018

I have enhanced spreadsheet such that it can perform some complex tasks of a macro. Here is a one liner that you can directly type into spreadsheet

Element27.Shape.Vertex1.Point.distanceToPlane(Element36.Shape.BoundBox.Center,Element36.Shape.Face1.Surface.Axis)

Or better, use labels,

Elements.<<$front>>.Shape.Vertex1.Point.distanceToPlane(Elements.<<$back>>.Shape.BoundBox.Center,Elements.<<$back>>.Shape.Face1.Surface.Axis)

Or even better, break it into cells

#A1
Elements.<<$back>>.Shape.Face1
#A2
Elements.<<$front>>.Shape.Vertex1.Point
#A3
A1.distanceToPlane(A2.BoundBox.Center,A2.Surface.Axis)

You see how it can replace macros? I think I'll further enhance the spreadsheet cell to accept parameters. Then it can really be a macro.

@ceremcem
Copy link
Collaborator Author

Much easier to use and provides some more advanced usage scenarios than using with macro.

@ceremcem
Copy link
Collaborator Author

ceremcem commented Sep 15, 2018

One question: How can we perform mathematical operations with the output of A1.distanceToPlane(A2.BoundBox.Center,A2.Surface.Axis) and a cell that contains unit?

Problem is that currently it seems to fail "16 mm" + 3.5.

@realthunder
Copy link
Owner

Times 1mm

@ceremcem
Copy link
Collaborator Author

I have created an Element and its type reveals as <App::FeaturePython object> which doesn't seem to have a .Shape property. Shouldn't all the Elements have <Part::PartFeature> type or are there any distinction between Elements?

@realthunder
Copy link
Owner

That shouldn't be possible. Every Eelement should be PartFeature. Are you sure this is not a ElementLink?

@ceremcem
Copy link
Collaborator Author

ceremcem commented Sep 16, 2018

Aha! Yes, I just found too: the previous enhancement (#70) requires it to be possible to duplicate labels, so ...getObjectsByLabel('foo')[0] shouldn't be blindly used:

>>> App.ActiveDocument.getObjectsByLabel('ref-support-back')
[<App::FeaturePython object>, <Part::PartFeature>, <App::FeaturePython object>]

@ceremcem
Copy link
Collaborator Author

Question: Can we use a constraint for the purpose? It would be a lot easier to declare/maintain a dynamic distance by using constraints (or, maybe, a virtual constraint?).

@realthunder
Copy link
Owner

I sure can. Be careful, though, distance measured this way cannot be used by any object inside the same assembly or any of its child assembly.

@ceremcem
Copy link
Collaborator Author

distance measured this way cannot be used by any object inside the same assembly or any of its child assembly

Same reason of #98 (comment), right? I think that might be somehow possible (because we do this in real life) but I need to think about this calmly. Until that time, it's okay to avoid using such "cyclic dependency" cases.

@ceremcem
Copy link
Collaborator Author

Taking the request one step further: It would be great to have a

  • Caliper tool that will produce the absolute value of distance between the elements.
  • Decides the type of method (distanceToPoint, distanceToPlane, distanceToLine) to use depending on the element geometry.

@realthunder
Copy link
Owner

  • Caliper tool that will produce the absolute value of distance between the elements.

What do you mean by Caliper tool? A button on the toolbar?

@ceremcem
Copy link
Collaborator Author

A button in the toolbar, just like constraint buttons, something like that:

dynamic-caliper

@realthunder
Copy link
Owner

Yep, sure.

realthunder added a commit that referenced this issue Sep 22, 2018
@ceremcem
Copy link
Collaborator Author

ceremcem commented Sep 23, 2018

I'm not sure if you released the tools or not, but current version includes the tools, thank you.

However, they give the following exception:

<asm3.main> 0.003646 - assembly.py(2583): solver exception when auto recompute
Traceback (most recent call last):
  File "/opt/FreeCAD/Ext/freecad/asm3/FCADLogger.py", line 83, in _catch
    return func(*args,**kargs)
  File "/opt/FreeCAD/Ext/freecad/asm3/solver.py", line 407, in solve
    return _solve(*args,**kargs)
  File "/opt/FreeCAD/Ext/freecad/asm3/solver.py", line 355, in _solve
    objs = FreeCAD.getDependentObjects(assemblies,False,True)
TypeError: function takes at most 2 arguments (3 given)
OS: Debian GNU/Linux 9.5 (stretch)
Word size of OS: 64-bit
Word size of FreeCAD: 64-bit
Version: 0.18.15558 (Git)
Build type: Debug
Branch: LinkStage3
Hash: 68bd55d8ab4acbea944be94350c295a84f5a9deb
Python version: 2.7.13
Qt version: 4.8.7
Coin version: 4.0.0a
OCC version: 7.1.0
Locale: English/UnitedStates (en_US)

@realthunder
Copy link
Owner

Please sync asm3 repo

@ceremcem
Copy link
Collaborator Author

ceremcem commented Sep 23, 2018

Still having errors in an empty document (same exception)

realthunder added a commit that referenced this issue Sep 23, 2018
@realthunder
Copy link
Owner

oops, my mistake. Please try again

@ceremcem
Copy link
Collaborator Author

Exception is gone, it's okay. How could we use a MeasurementConstraint, say it's labeled as foo-bar-baz. Isn't it like:

=Elements.<<$foo-bar-baz>>.Distance

@ceremcem
Copy link
Collaborator Author

ceremcem commented Sep 23, 2018

Upps, it seems it's like:

=foo_bar_baz.Distance

(don't use dashed labels when you are going to refer it within a spreadsheet)

@ceremcem
Copy link
Collaborator Author

Label2 (what is that?) is confusing when we replaced an element and recalculated:

image

realthunder added a commit to realthunder/FreeCAD that referenced this issue Sep 24, 2018
PropertyExpressionEngine::execute() can be divided to two steps, to
compute non-output properties before object execute(), and then compute
only output propertyies afterwards.

Fixes realthunder/FreeCAD_assembly3#52
@realthunder
Copy link
Owner

Label2 is my experiment of supporting user defined descriptional information of an object. It is shown in the tree view as a second Description column. The measurement is the first example of using it. The content of the Label2 here is actually an expression binding to Distance, which can be changed by the user. A second future example would be showing DOF of each part in an assembly. I will add more string formatting expression later on to support more possibilities..

@ceremcem
Copy link
Collaborator Author

Wow! Nice! That was something I was thinking about. My actual target was related with SheetMetal WB, where if we could embed an information into a line - like "95 degree, bend towards XXX direction" - so that the TechDraw WB can use that information to generate additional markings. Nice feature!

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Development

No branches or pull requests

2 participants