Salusoft89 / planegcs

A webassembly wrapper for FreeCAD's 2D geometric solver.
https://www.npmjs.com/package/@salusoft89/planegcs
GNU Lesser General Public License v2.1
24 stars 9 forks source link

Arc primitive question #3

Open ostryhub opened 3 months ago

ostryhub commented 3 months ago

Hi @thes01.

I am implementing Arc primitive in my sketcher app using this great wrapper lib, thank you for making it!

When looking at how arcs are defined I am having trouble understanding why it needs start and end angles on top of the three points ?

I am looking to implement the "center arc curve" in the very same way FreeCAD does its, so I am interested in defining three points of the arc (a, b and center) and hope the solver to keep them constrained to the arc's defining circle. I want the arc to "float freely in 2d space" in its most basic setup (without any additional constraints) by just keeping the a and b points the same distance form the center point.

Could you explain how the planegcs's arc primitive is meant to be used and in what scenarios? Why the start and end angles are needed to define it?

Is my intuition right when I think that the FreeCAD like arc curve can be implemented using a set of other primitives like three points and a circle plus constraints keeping the arc end points on the circle and the arc center coincident with the circle's center?

Thank you for any answer to this questions.

thes01 commented 3 months ago

Hello @ostryhub :) Thank you for the question.

It is connected to how planegcs internally represents the constraints and the geometrical objects. The "arc relationship" is defined by the arc_rules primitive constraint, as described in the README.md:

{ id: '6', type: 'arc_rules', a_id: '5' }. Without it, the points can be freely moved without the solver caring. To enforce the constraint, planegcs internally uses the start_angle and end_angle values, because it corresponds to the degrees of freedom reduced by the constraint (2) (or in other words: it's the least number of parameters that you need for describing this particular relationship).

Also note that this constraint doesn't enforce the radius of the arc, it just says "the arc's start/end points are really endpoints" :)


I'll give a slightly different example to make the point:

Imagine a circle with the center in [0, 0] and having radius 10. Now given that - what is the least number of values to uniquely identify a point on that circle? You can think of [x,y] coordinates of the point, but actually only one - [angle] - is necessary (and it's even better because it's independent on the radius and center).

For all possible [x,y], there's a lot of invalid options that would break the definition of the circle. However, all values of angle give rise to a valid point on the circle (and by sin/cos functions you can derive the [x,y] values).


As planegcs is quite a low-level library, it uses the least number of values for the solver constraints. In the case of the arc, those are the start_angle and end_angle that are the basis for the constraint, instead of the start/end points' coordinates.

There's some experiments you can do with planegcs: If you fix all your arc points with fixed: true, and set their coordinates to correct (precomputed) positions, then the solver would compute the start angle and end angle to align them with the points. Or alternatively, you can also let the coordinates be random and not fixed and instead fix the start_angle and end_angle values by adding an equal constraint (see code below). Now planegcs should compute the points positions based on the start/end angle values. (You may need to still fix the center point).

{ 
   id: '10', 
   type: 'equal',
   param1: {
      o_id: '3', // arc id
      prop: 'start_angle',
   },
   param2: 0, // the value of the angle in radians
}

So basically that's the why. What I've been doing is that I just precompute the start_ and end_angle based on my start/end points positions so that the solver has everything "prepared" and thereby reduce the number of iteration. This is a general principle - everything that can be precomputed should be precomputed to simplify the solver's work :).

I hope that helps :)

Also, I would like to mention that I've been working on a "builder API" for the planegcs primitives that could be more closely related to how you construct sketch geometries in FreeCAD's python API (though not precisely the same). I'm still iterating on the API design, but it should be simpler to use it compared to the raw planegcs primitives.

ostryhub commented 3 months ago

Thank you for the detailed explanation. I did not realize that you can constrain the primitive params directly, thats gonna be definitely useful. Also I did figure out where my confusion was coming from. I did set the arc as described in the readme secion yet when defined by 3 spoints, arc primitive + arc_rules constraint I would still not see the arc relations being maintained when dragging the points. After closer inspection I realised that when defining arc_rules constraint I simply missed setting the "driving" property to true. With that "little" fix I can now see my arc behaving as expected.

Thank you very much for the detailed answer and I am sure I will be asking more questions soon as I am planning to get the "full" sketcher functionality working for my app.

thes01 commented 3 months ago

I'm glad it helped. Anyway, would you be interested in discussing the higher-level sketcher API? I think it would help me to see a different point of view. I'll prepare a new branch with what I currently have.

ostryhub commented 3 months ago

Yes, sure, I will be happy to help! (and also get more undestanding on how things are intended to be used)