## Shake sketch (poor-man freedom relevator)

Need help, or want to share a macro? Post here!
galou_breizh
Posts: 322
Joined: Wed Sep 15, 2010 9:38 am

### Shake sketch (poor-man freedom relevator)

Hi,

I wrote a little macro that could help people visualize where the degrees of freedom are in a sketch. The principle is very simple, a random noise is added in all points and the sketch is then solved. What is free moves what is constrained does not.

I'll post it on the wiki if you find it useful and bug-free (at least with only few bugs).

I you think it's a good idea, I'll do a command out of it.

If someone is motivating to create an icon, please do it!

Gaël

FCMacro extension are not allowed as attachment so I include the macro directly:

Code: Select all

``````# -*- coding: utf-8 -*-

# FreeCAD macro to shake a sketch in order to discover its unconstrained parts.
#
# A Gaussian noise is introduced in all sketch points and the sketch is then
# solved.
# Beware that the sketch can look different because some constraints have
# several solutions. In this case, just undo.
#
# This file is released under the MIT License.
# Author: Gaël Ecorchard
# Version: 1.0, 2014-08, first release.

# Amplitude of the point displacements.
# The standard deviation of the Gaussian noise is the largest sketch dimension
# multiplied by this factor.
displacement_amplitude = 0.1

# End of configuration.

from random import gauss

# For each sketch geometry type, map a list of points to move.
geom_points = {
'point': [1],
'line': [1, 2],  # first point, last point
'circle': [0, 3],  # curve, center
'arc': [1, 2, 3],  # first point, last point, center
}

class BoundingBox(object):
xmin = None
xmax = None
ymin = None
ymax = None

def enlarge_x(self, x):
if self.xmin is None:
self.xmin = x
self.xmax = x
return
if self.xmin > x:
self.xmin = x
return
if self.xmax < x:
self.xmax = x
return

def enlarge_y(self, y):
if self.ymin is None:
self.ymin = y
self.ymax = y
return
if self.ymin > y:
self.ymin = y
return
if self.ymax < y:
self.ymax = y
return

def enlarge_point(self, point):
self.enlarge_x(point.x)
self.enlarge_y(point.y)

def enlarge_line(self, line):
self.enlarge_x(line.StartPoint.x)
self.enlarge_x(line.EndPoint.x)
self.enlarge_y(line.StartPoint.y)
self.enlarge_y(line.EndPoint.y)

def enlarge_circle(self, circle):

def enlarge_arc_of_circle(self, arc):
# TODO: correctly compute the arc extrema (cf. toShape().BoundBox)
self.enlarge_x(arc.Center.x)
self.enlarge_y(arc.Center.y)

def get_sketch_dims(sketch):
bbox = BoundingBox()
for geom in sketch.Geometry:
if isinstance(geom, Base.Vector):
bbox.enlarge_point(geom)
elif isinstance(geom, Part.Line):
bbox.enlarge_line(geom)
elif isinstance(geom, Part.Circle):
bbox.enlarge_circle(geom)
elif isinstance(geom, Part.ArcOfCircle):
bbox.enlarge_arc_of_circle(geom)
if (bbox.xmin is not None) and (bbox.ymin is not None):
return bbox.xmax - bbox.xmin, bbox.ymax - bbox.ymin
else:
return 0, 0

"""Add a Gaussian noise with standard deviation sigma"""
point.x = gauss(point.x, sigma)
point.y = gauss(point.y, sigma)

def move_points(sketch, geom_index, point_indexes, sigma):
# however prevent repeated recompute.
for point_index in point_indexes:
point = sketch.getPoint(geom_index, point_index)
sketch.movePoint(geom_index, point_index, point)

view_provider = Gui.activeDocument().getInEdit()

# Don't know how to exit from a macro.
do_move = True
if not view_provider:
do_move = False

if do_move:
sketch = view_provider.Object

if sketch.TypeId != 'Sketcher::SketchObject':
do_move = False

if do_move:
sigma = max(get_sketch_dims(sketch)) * displacement_amplitude

for i, geom in enumerate(sketch.Geometry):
if isinstance(geom, Base.Vector):
move_points(sketch, i, geom_points['point'], sigma)
elif isinstance(geom, Part.Line):
move_points(sketch, i, geom_points['line'], sigma)
elif isinstance(geom, Part.Circle):
move_points(sketch, i, geom_points['circle'], sigma)
elif isinstance(geom, Part.ArcOfCircle):
move_points(sketch, i, geom_points['arc'], sigma)
``````
wmayer
Posts: 16460
Joined: Thu Feb 19, 2009 10:32 am

### Re: Shake sketch (poor-man freedom relevator)

Might be useful for this issue: issue #1041
bejant
Posts: 6076
Joined: Thu Jul 11, 2013 3:06 pm

### Re: Shake sketch (poor-man freedom relevator)

I made a Sketch from a Polyline in a zig-zag pattern, then used the Constraints Lock tool on some vertices, and left some others unconstrained. I ran the macro and it worked well and I like that the Sketch reverts back to the original orientation when Undo is used afterwards. So when Undo is used, the user has another chance the see the unconstrained entities move. As a suggestion, I think it would be even more helpful (especially to novices) if the things that moved when running this macro were also highlighted as mentioned in ticket 1041.
arcol
Posts: 223
Joined: Sun Nov 10, 2013 9:02 am

### Re: Shake sketch (poor-man freedom relevator)

Can somebody enlightens me how this is supposed to work?

I saved the macro under ~/.FreeCAD/constraints_find.FCMacro

I changed this line:

Code: Select all

``````from FreeCAD import Part
``````
to this:

Code: Select all

``````import Part
``````
The macro is listed under the Macro menu.
I can execute it, but nothing happens.

I suppose it should work like this:
[*] open the sketch
[*] Macro->Macros->constraints_find->EXECUTE
[*] Something should happen.

Any ideas?
jmaustpc
Posts: 10203
Joined: Tue Jul 26, 2011 6:28 am
Location: Australia

### Re: Shake sketch (poor-man freedom relevator)

do you have any messages in report view?

For that matter, have you changed your FreeCAD preferences to redirect errors and Python messages to report view?
NormandC
Posts: 18534
Joined: Sat Feb 06, 2010 9:52 pm

### Re: Shake sketch (poor-man freedom relevator)

arcol wrote:Any ideas?
Sorry if I seem obvious, but if your sketch is fully constrained, nothing will happen.

After doing your change to the script, the macro works for me as expected. Elements that are unconstrained get moved.

OS: Ubuntu 14.04.1 LTS
Word size of OS: 64-bit
Version: 0.15.4138 (Git)
Branch: master
Hash: f119e740c87918b103140b66b2316ae96f136b0e
Python version: 2.7.6
Qt version: 4.8.6
Coin version: 4.0.0a
OCC version: 6.7.1
arcol
Posts: 223
Joined: Sun Nov 10, 2013 9:02 am

### Re: Shake sketch (poor-man freedom relevator)

jmaustpc wrote:do you have any messages in report view?

For that matter, have you changed your FreeCAD preferences to redirect errors and Python messages to report view?
Yes, I did:
freecad_preference_general_output.png (130.7 KiB) Viewed 5213 times
No output from the macro. I added a print statement at the end, and I see it in the report dialog each time I execute the macro:

Code: Select all

``````Active view is challenge_constraint_macro : 1[*] (at 0x57d7f30)
Tried to move all points by a random value
``````
At the end of the macro file:

Code: Select all

``````print "Tried to move all points by a random value"
``````
normandc wrote: Sorry if I seem obvious, but if your sketch is fully constrained, nothing will happen.

After doing your change to the script, the macro works for me as expected. Elements that are unconstrained get moved.
It was not fully constrained, but had 3 degrees of freedom, with 43 contraints already placed.

I player a bit more, and created some test sketches, and with a very basic sketch (a single rectangle) the points indeed move ONCE.

I was expecting some actual shaking.

But for my test file, it does exactly nothing.
Here is it attached (I attached in this thread originally):
challenge_constraint_macro.fcstd
Does this macro works for anybody with the above testfile?

Normandc: To better word the problem: I can't figure out where should I put the missing constraints. And why I'm unable to move a single point in the sketch. Any idea?
ulrich1a
Posts: 1958
Joined: Sun Jul 07, 2013 12:08 pm

### Re: Shake sketch (poor-man freedom relevator)

arcol wrote:It was not fully constrained, but had 3 degrees of freedom, with 43 contraints already placed.

I player a bit more, and created some test sketches, and with a very basic sketch (a single rectangle) the points indeed move ONCE.
I was expecting some actual shaking.
But for my test file, it does exactly nothing.
It seems your sketch has redundant constraints. Sketches with more than one redundant constraints do not move at all in most cases.
The sketch had two symmetry constraints at the same location. And there was a perpendicular constraint at the two construction lines. If one of the symmetry constraints is against the one construction line and not a point, the perpendicular constraint could be redundant. It is very easy to make redundant constraints in combination with the symmetry constraint, that are not detected by the sketcher solver. For me it seems also the Shake sketch macro do not help in this case, as it do not detect the redundant constraints.
After removing the two symmetry constraints and the perpendicular constraint, I was able to fully constrain the sketch with a little different approach.
For a discussion about redundant constraints have a look into the sketcher tutorial, in the FreeCAD-tutorial collection.

Ulrich
bejant
Posts: 6076
Joined: Thu Jul 11, 2013 3:06 pm

### Re: Shake sketch (poor-man freedom relevator)

arcol, the way I used the original macro was to copy and paste it into the python console, with a Sketch open for editing, then press the Enter key...

After making your change to the macro it worked for me by selecting it from Macro > Macros, the pressing the Execute button.

It only "shakes" the sketch once. You can undo / redo for a shaking effect, but I too didn't see anything move in your Sketch02.