How to use arcs.py arcFrom2Pts

Need help, or want to share a macro? Post here!
Forum rules
Be nice to others! Respect the FreeCAD code of conduct!
drmacro
Veteran
Posts: 8987
Joined: Sun Mar 02, 2014 4:35 pm

Re: [possible bug] in arcs.py arcFrom2Pts

Post by drmacro »

edwilliams16 wrote: Sun May 02, 2021 1:27 am ...
https://wiki.freecadweb.org/Sandbox:Edwilliams16 is about Vector algebra in FreeCAD.
So, reading through this link, some ancient light is glimmering in my brain.

I have 3 vectors. All of which happen to have z=0
  • start vector
  • end vector
  • center (as in center point of the arc)
I think I need the start angle around the normal to the center.
And the end angle around the normal to the center.

To get those I need to translate the vectors so they are relative to the center, not the global origin.
That part of my brain has apparently atrophied to a, possibly, irretrievable degree. :(

I'm not seeing how to use vector math to get these...and, maybe I'm just making it too difficult. :oops: :(
Star Trek II: The Wrath of Khan: Spock: "...His pattern indicates two-dimensional thinking."
edwilliams16
Veteran
Posts: 3184
Joined: Thu Sep 24, 2020 10:31 pm
Location: Hawaii
Contact:

Re: How to use arcs.py arcFrom2Pts

Post by edwilliams16 »

Code: Select all

import FreeCAD
from FreeCAD import Rotation, Vector
import Part

def semicircleFrom2Pts(firstPt, lastPt, normal = Vector(0, 0 ,1)):
    """Build a semicircle between 2 points, ccw around the normal vector."""
    center = (firstPt + lastPt)/2
    radiusVector = firstPt - center
    rot = Rotation(normal, 90)
    intermediatePt = center + rot.multVec(radiusVector)
    newArc = Part.Edge(Part.Arc(firstPt, intermediatePt, lastPt))
    return newArc
Try the above. It constructs the intermediate point by rotating the radiusVector 90 degrees.

Tested with

Code: Select all

firstPt = Vector(1, 0, 0)
lastPt = Vector(-1, 0 ,0)
semiccw = semicircleFrom2Pts(firstPt, lastPt)
semicw = semicircleFrom2Pts(firstPt, lastPt, Vector(0, 0, -1))
Part.show(semiccw)
edwilliams16
Veteran
Posts: 3184
Joined: Thu Sep 24, 2020 10:31 pm
Location: Hawaii
Contact:

Re: How to use arcs.py arcFrom2Pts

Post by edwilliams16 »

Code: Select all

import FreeCAD
from FreeCAD import Rotation, Vector
import Part

def semicircleFrom2Pts(firstPt, lastPt, normal = Vector(0, 0 ,1)):
    """Build a semicircle between 2 points, ccw around the normal vector."""
    center = (firstPt + lastPt)/2
    radiusVector = firstPt - center
    rot = Rotation(normal, 90)
    intermediatePt = center + rot.multVec(radiusVector)
    newArc = Part.Edge(Part.Arc(firstPt, intermediatePt, lastPt))
    return newArc

def arcFromCenter2Pts(firstPt,lastPt, center, ccw = True, normal = Vector(0, 0, 1)):
    """ Build a ccw arc from firstPt to LastPt around center. The normal direction
    argument for the plane containing the arc is unused unless firstPt, lastPt and center are collinear
    and therefore do not themselves define the plane"""
    r1 = firstPt - center
    r2 = lastPt - center
    rad1 = r1.Length
    rad2 = r2.Length
    if rad1 < 1e-7 or rad2 <1e-7:  #zero radius arc
        return None
        # (PREC = 4 = same as Part Module),  Is it possible?
    if round(rad1-rad2, 4) != 0:
        return None
    if round(r1.cross(r2).Length, 4) == 0:  #semicircle case
        if ccw:
            return semicircleFrom2Pts(firstPt, lastPt, normal)
        else:
            return semicircleFrom2Pts(firstPt, lastPt, -normal)
    else:  #arc case
        if ccw:
            rot = Rotation(r1, r2) # rotates r1 into r2
        else:
            rot = Rotation(r2, r1)
        identity = Rotation(0,0,0,1)
        rothalf = rot.slerp(identity, 0.5) #rotate by half the angle
        intermediatePt = center + rothalf.multVec(r1)
        newArc = Part.Edge(Part.Arc(firstPt, intermediatePt, lastPt))
        return newArc
For posterity, this routine should cover all the edge cases (I've thought of!)
drmacro
Veteran
Posts: 8987
Joined: Sun Mar 02, 2014 4:35 pm

Re: How to use arcs.py arcFrom2Pts

Post by drmacro »

edwilliams16 wrote: Sun May 02, 2021 7:07 pm
I won't be able to look at these until tomorrow, but am keen to learn from them.

Thank you!
Star Trek II: The Wrath of Khan: Spock: "...His pattern indicates two-dimensional thinking."
drmacro
Veteran
Posts: 8987
Joined: Sun Mar 02, 2014 4:35 pm

Re: How to use arcs.py arcFrom2Pts

Post by drmacro »

The questions begin...

In both of the routines you posted above the return is:

Code: Select all

newArc = Part.Edge(...
But, when I use that return with:

Code: Select all

endarc=arcFromCenter2Pts(outerendvec, innerendvec, endarc_cen)
L2=CurDoc.addGeometry(endarc)
It produces the error:

Code: Select all

<class 'TypeError'>: type must be 'Geometry' or list of 'Geometry', not Part.Edge
I admit I'm still not clear on why FC has topological and geometry. I've read it here https://wiki.freecadweb.org/Topological_data_scripting and @Chris_G answered my query about it in another post. I see that is Topology is a sort of wrapper around lesser geometries...but, it just seems to be obfuscation for no particular benefit at my current level of understanding.

Add that Part.Arc( and Part.ArcOfCircle( and Part.Circle( all appear to return Geometry...and Part.Edge( returns Topology.

Why isn't it Part.Geom.Arc( or Part.Geom.Circle( and Part.Topo.Edge(
(Geom & Topo being made up by me for example)

It just seems the object model is bloated and obfuscating...again, probably my understanding level.

I'm guessing that the Geometry object of the Arc I seek IS in the returned Topo, (I've looked at the returned object at a breakpoint and not found the arc Geometry.)

But, I can't figure out how to make this work:

Code: Select all

endarc=arcFromCenter2Pts(outerendvec, innerendvec, endarc_cen)
L2=CurDoc.addGeometry(endarc)
Star Trek II: The Wrath of Khan: Spock: "...His pattern indicates two-dimensional thinking."
User avatar
onekk
Veteran
Posts: 6215
Joined: Sat Jan 17, 2015 7:48 am
Contact:

Re: How to use arcs.py arcFrom2Pts

Post by onekk »

EDIT: I have fully misunderstood your post, (if you have read the unedited post, sorry) in Sketcher addGeometry() has some sense.

But as chrisb has told you in another thread, not every thing has a geometry meaning.
topology is a layer above geometry curves (circle, line, ellipse, Bezier, ...) and surfaces (sphere, plane, toroid, bezier, bspline, ...)
So they are some other thing are simply as found in:

https://dev.opencascade.org/doc/occt-7. ... _data.html
Computation of the coordinates of points on 2D and 3D curves
Those "computed points" are not necessarily an Edge, (FreeCAD could have also edges that are "portions of a curve"), but if this "portion of a curve" is simply a "descriptions of the points" it ihas no "topological meaning" and have to be "promoted" to became a proper "topological data".

From what arise many errors like "object is not and Edge" as example when the method is expecting an "Edge".

as told by chrisb:
So the 3 BASE topology object always has an underlying geometry :
- a Part.Vertex is the topological wrapper of a FreeCAD.Vector (myVertex.Point)
- a Part.Edge is the topological wrapper of a Geometry Curve (myEdge.Curve) between 2 bounds (myEdge.ParameterRange)
- a Part.Face is the topological wrapper of a Geometry Surface (myFace.Surface) bounded by a outerWire and maybe some hole wires (myFace.Wires)
Note the expression "underlying geometry", and "topological wrapper".

maybe if you inspect the code using:

Code: Select all

print(dir(newArc))
As when dealing with Part things there is a method toShape() maybe there is a way to transform a Part.Edge in a Geometry objects.

EDIT2:
Maybe this page is new, and some thing are improving in documentation.

https://wiki.freecadweb.org/Sketcher_scripting

And chrib has done a very good introduction to sketcher as pdf document, I've download it and I'm studying.

Regards

Carlo D.
GitHub page: https://github.com/onekk/freecad-doc.
- In deep articles on FreeCAD.
- Learning how to model with scripting.
- Various other stuffs.

Blog: https://okkmkblog.wordpress.com/
edwilliams16
Veteran
Posts: 3184
Joined: Thu Sep 24, 2020 10:31 pm
Location: Hawaii
Contact:

Re: How to use arcs.py arcFrom2Pts

Post by edwilliams16 »

I just used the return type from the original code - only fixing the edge case of the semicircle. You can of course remove the Part.Edge() wrappers around the return if you need the geometry object.
I have very limited understanding of these issues. I just find some code that works and use it as a template. To draw a sketch from geometry, I would use https://github.com/FreeCAD/FreeCAD/blob ... Hexagon.py

As a template.

EDIT
If you need input from gui clicks, https://wiki.freecadweb.org/Line_drawing_function is a template.
drmacro
Veteran
Posts: 8987
Joined: Sun Mar 02, 2014 4:35 pm

Re: How to use arcs.py arcFrom2Pts

Post by drmacro »

edwilliams16 wrote: Mon May 03, 2021 3:53 pm I just used the return type from the original code - only fixing the edge case of the semicircle. You can of course remove the Part.Edge() wrappers around the return if you need the geometry object.
I have very limited understanding of these issues. I just find some code that works and use it as a template. To draw a sketch from geometry, I would use https://github.com/FreeCAD/FreeCAD/blob ... Hexagon.py

As a template.

EDIT
If you need input from gui clicks, https://wiki.freecadweb.org/Line_drawing_function is a template.
Thank you for the examples, they are now bookmarked for study and use.

As for the change suggested for Part.Edge() wrappers, yes, I actually had already done that in the original python that began this thread.

And, that works fine. My issue is I'd like to understand why it is presented thusly and why removal is needed for this case.

I think it has to do with the objects being used, in this case CurDoc.addGeometry():

Code: Select all

DocName=Gui.ActiveDocument.Document.Name
SkeName=Gui.ActiveDocument.getInEdit().Object
CurDoc=App.getDocument(DocName).getObject(SkeName.Name)
...
...
L3=CurDoc.addGeometry(endarc)
I just don't understand why and I think understanding it is important, if I don't want to making every line of python I write trial-n-error. 🤔
Star Trek II: The Wrath of Khan: Spock: "...His pattern indicates two-dimensional thinking."
edwilliams16
Veteran
Posts: 3184
Joined: Thu Sep 24, 2020 10:31 pm
Location: Hawaii
Contact:

Re: How to use arcs.py arcFrom2Pts

Post by edwilliams16 »

If I draw a line in sketcher, in the Python console I get:

Code: Select all

App.getDocument('Unnamed').getObject('Sketch').addGeometry(Part.LineSegment(App.Vector(-34.985630,7.614941,0),App.Vector(35.847698,13.218391,0)),False)
which tells me what kind of object the addGeometry method expects as an argument.

I take it that an Edge is a wrapper of Line which possesses additional properties that are unneeded, so the method works with the more primitive construct. But I don't understand the innards well enough to pin this down. Pragmatically, I try to understand the recipe before I embark on a theory of cooking.
drmacro
Veteran
Posts: 8987
Joined: Sun Mar 02, 2014 4:35 pm

Re: How to use arcs.py arcFrom2Pts

Post by drmacro »

edwilliams16 wrote:
I am looking through arcFromCenter2Pts, arc case and you Sandbox page.

r1 and r2 the vector from center to the end points of firstPt, lastPt respectively.

rot = Rotation(r1, r2) returns the angle between r1 & r2 (in radians)

identity = Rotation(0,0,0,1)
rothalf = rot.slerp(identity, 0.5) returns a vector that bisects the arc between r1 & r2 ?????

intermediatePt = center + rothalf.multVec(r1) returns the point that bisects the arc?
Star Trek II: The Wrath of Khan: Spock: "...His pattern indicates two-dimensional thinking."
Post Reply