Optical constraints development [Win64 build available]

Here's the place for discussion related to coding in FreeCAD, C++ or Python. Design, interfaces and structures.
User avatar
DeepSOIC
Posts: 6876
Joined: Fri Aug 29, 2014 12:45 am
Location: Saint-Petersburg, Russia

Optical constraints development [Win64 build available]

Postby DeepSOIC » Wed Dec 10, 2014 10:10 pm

Hi everyone!
Just to make people aware, I have started development of optical constraints for the Sketcher. I'm doing the development for myself, and will be glad to make a pull request if there is demand.
I'm doing the development on top of my latest AngleViaPoint branch. It's not in master yet (and I'm not sure if it will ever make it there).
The plan: two constraints. One for a ray passing through a boundary, and another one for a ray reflecting off a boundary. The first one will be a datum, holding a ratio of refraction indexes.
I will be glad to hear suggestions if someone happens to have some. I'd be glad, if Jim (or whoever) helps me with icons :roll: [no need anymore].

The reason for making the constraints is convenience and speed. I can do the trick by geometric constructions, but it is a lot of work even for just two refractions, and it becomes slow as a dead cow really too quickly. Also the mess near the point of refraction... not really pleasant to look at.

The development branch: OpticConstraints. Snell's law constraint is completed. Reflection constraint will not be started, as it is covered by Snell's law constraint.

Right now I'm refactoring some core stuff to simplify analytic derivative calculations.
Last edited by DeepSOIC on Sat Dec 13, 2014 5:40 pm, edited 6 times in total.
User avatar
DeepSOIC
Posts: 6876
Joined: Fri Aug 29, 2014 12:45 am
Location: Saint-Petersburg, Russia

Re: Optical constraints development

Postby DeepSOIC » Thu Dec 11, 2014 8:58 pm

I have done another fundamental change to GCS. I'm very proud of it.
The change allows to do vector math in error functions without calculating partials - the code to calculate partials now coincides with the code to calculate the error function.
It was done by converting GCS::Vector2D into GCS::DeriVector2. The new vector class has two additional fields (dx,dy) to store vector's derivative on current parameter.


So, the calculation of ellipse's normal vector and its derivatives used to be like this:

Code: Select all

//--------------ellipse
171	Vector2D Ellipse::CalculateNormal(Point &p, double* derivparam)
172	{
173	    Vector2D cv (*center.x, *center.y);
174	    Vector2D f1v (*focus1X, *focus1Y);
175	    Vector2D pv (*p.x, *p.y);
176	
177	    Vector2D ret(0.0, 0.0);
178	
179	    Vector2D f2v ( 2*cv.x - f1v.x, 2*cv.y - f1v.y ); //position of focus2
180	    if(derivparam){
181	
182	        Vector2D dc;
183	        Vector2D df1;
184	        Vector2D dp;
185	
186	        if (derivparam == center.x) dc.x = 1.0;
187	        if (derivparam == center.y) dc.y = 1.0;
188	        if (derivparam == focus1X) df1.x = 1.0;
189	        if (derivparam == focus1Y) df1.y = 1.0;
190	        if (derivparam == p.x) dp.x = 1.0;
191	        if (derivparam == p.y) dp.y = 1.0;
192	        //todo: exit if all are zero
193	
194	        Vector2D pf1 = Vector2D(pv.x - f1v.x, pv.y - f1v.y);//same as during error function calculation. I reuse the values during derivative calculation
195	        Vector2D pf2 = Vector2D(pv.x - f2v.x, pv.y - f2v.y);
196	        Vector2D pf1e = pf1.getNormalized();
197	        Vector2D pf2e = pf2.getNormalized();
198	
199	        Vector2D df2 (2*dc.x - df1.x, 2*dc.y - df1.y );
200	
201	        Vector2D dpf1 (dp.x - df1.x, dp.y - df1.y);//derivative before normalization
202	        Vector2D dpf1e (dpf1.x/pf1.length(), dpf1.y/pf1.length());//first portion of normalization derivative (normalized' = unnormalized'/len + unnormalized*(1/len)')
203	        dpf1e.x += -pf1.x/pow(pf1.length(),2)*(dpf1.x*pf1e.x + dpf1.y*pf1e.y);//second part of normalization dreivative
204	        dpf1e.y += -pf1.y/pow(pf1.length(),2)*(dpf1.x*pf1e.x + dpf1.y*pf1e.y);
205	
206	        Vector2D dpf2 (dp.x - df2.x, dp.y - df2.y);//same stuff for pf2
207	        Vector2D dpf2e (dpf2.x/pf2.length(), dpf2.y/pf2.length());//first portion of normalization derivative (normalized' = unnormalized'/len + unnormalized*(1/len)')
208	        dpf2e.x += -pf2.x/pow(pf2.length(),2)*(dpf2.x*pf2e.x + dpf2.y*pf2e.y);//second part of normalization dreivative
209	        dpf2e.y += -pf2.y/pow(pf2.length(),2)*(dpf2.x*pf2e.x + dpf2.y*pf2e.y);
210	
211	        ret.x = -(dpf1e.x + dpf2e.x);
212	        ret.y = -(dpf1e.y + dpf2e.y);//DeepSOIC: derivative calculated manually... error-prone =) Tested, fixed, looks good.

.........(numeric derivative testing code skipped)
232	
233	    } else {
234	        Vector2D pf1 = Vector2D(pv.x - f1v.x, pv.y - f1v.y);
235	        Vector2D pf2 = Vector2D(pv.x - f2v.x, pv.y - f2v.y);
236	        Vector2D pf1e = pf1.getNormalized();
237	        Vector2D pf2e = pf2.getNormalized();
238	        ret.x = -(pf1e.x + pf2e.x);
239	        ret.y = -(pf1e.y + pf2e.y);
240	    };
241	
242	    return ret;
243	}
Now, this is simply:
(both the normal vector and derivative are calculated at the same time)

Code: Select all

DeriVector2 Ellipse::CalculateNormal(Point &p, double* derivparam)
182	{
183	    //fill some vectors in
184	    DeriVector2 cv (center, derivparam);
185	    DeriVector2 f1v (focus1, derivparam);
186	    DeriVector2 pv (p, derivparam);
187	
188	    //calculation.
189	    //focus2:
190	    DeriVector2 f2v = cv.linCombi(2.0, f1v, -1.0); // 2*cv - f1v
191	
192	    //pf1, pf2 = vectors from p to focus1,focus2
193	    DeriVector2 pf1 = f1v.subtr(pv);
194	    DeriVector2 pf2 = f2v.subtr(pv);
195	    //return sum of normalized pf2, pf2
196	    DeriVector2 ret = pf1.getNormalized().sum(pf2.getNormalized());
197	
.........(numeric derivative testing code skipped)
218	
219	    return ret;
220	}
This was done to:
+ simplify understanding of the math.
+ eliminate hassle of derivative calculation, thus simplifying adding new constraints.
+ hugely simplify testing of different error function formulations
+ reduce potential for mistakes
The drawbacks are:
- for newcomers, it may be not trivial to understand how the derivatives are actually calculated.
- the derivatives are less simplified, so there is performance drop.
- Derivative calculation code gets executed even when there is no need to do so (e.g. when calculating error() ), but since error calculations are executed O(n) times compared to O(n^2) for derivatives, this isn't much of a penalty.
User avatar
DeepSOIC
Posts: 6876
Joined: Fri Aug 29, 2014 12:45 am
Location: Saint-Petersburg, Russia

Re: Optical constraints development

Postby DeepSOIC » Fri Dec 12, 2014 10:39 pm

OK, adding a new constraint to the UI was quite a lot of digging, but it starts to work...
Attachments
Snell's law starts to work.png
Snell's law starts to work.png (143.18 KiB) Viewed 2128 times
User avatar
DeepSOIC
Posts: 6876
Joined: Fri Aug 29, 2014 12:45 am
Location: Saint-Petersburg, Russia

Re: Optical constraints development

Postby DeepSOIC » Sat Dec 13, 2014 12:37 am

Application example. Deriving apparent position of a point viewed through a glass plate.
Attachments
Snell's law slab.png
Snell's law slab.png (17.54 KiB) Viewed 2109 times
User avatar
DeepSOIC
Posts: 6876
Joined: Fri Aug 29, 2014 12:45 am
Location: Saint-Petersburg, Russia

Re: Optical constraints development

Postby DeepSOIC » Sat Dec 13, 2014 2:51 pm

Snell's law constraint is finished :mrgreen:
User avatar
DeepSOIC
Posts: 6876
Joined: Fri Aug 29, 2014 12:45 am
Location: Saint-Petersburg, Russia

Re: Optical constraints development

Postby DeepSOIC » Sat Dec 13, 2014 3:05 pm

The reflection constraint can be achieved by applying a snell's law constraint with ratio set to 1, so I'm not going to do it. I'm finished!
Attachments
snell's law for reflection.png
snell's law for reflection.png (93.88 KiB) Viewed 2065 times
User avatar
DeepSOIC
Posts: 6876
Joined: Fri Aug 29, 2014 12:45 am
Location: Saint-Petersburg, Russia

Re: Optical constraints development

Postby DeepSOIC » Sat Dec 13, 2014 4:52 pm

The thing, together with sketcher ellipse and angle-via-point constraint, are now rebased onto the master.
User avatar
DeepSOIC
Posts: 6876
Joined: Fri Aug 29, 2014 12:45 am
Location: Saint-Petersburg, Russia

Re: Optical constraints development

Postby DeepSOIC » Sat Dec 13, 2014 5:38 pm

[OBSOLETE!]
Windows 64-bit build:
https://drive.google.com/file/d/0B9lBm- ... sp=sharing
(164 MB zip archive)
Unpack, run bin\FreeCAD.exe.
Use caution. I did not scan it for viruses :oops: .
Please! Report any problems! Enjoy.

OS: Windows 8.1
Word size of OS: 64-bit
Word size of FreeCAD: 64-bit
Version: 0.15.4269 +37 (Git)
Branch: OpticConstraints
Hash: d648ab583be8cc67a9ebb17d0b26a4438c291cd4
Python version: 2.7.8
Qt version: 4.8.6
Coin version: 4.0.0a
OCC version: 6.7.1
Last edited by DeepSOIC on Tue Dec 16, 2014 12:03 am, edited 1 time in total.
jmaustpc
Posts: 9558
Joined: Tue Jul 26, 2011 6:28 am
Location: Australia

Re: Optical constraints development [Win64 build available]

Postby jmaustpc » Sun Dec 14, 2014 11:32 am

Hi DeepSOIC

I had an attempt at an icon set for you today. Do you like these?

There is two constraints, reflection and refraction. I then thought perhaps an eye (or something else) might be a good idea to differentiate these constraints from the more common type. This is what it could look like with a black symbolic eye.

I have created the matching xpm files with a white cross, for the mouse cursors.
optics_sketcher_icons.jpeg
optics_sketcher_icons.jpeg (24.98 KiB) Viewed 2000 times
and here are all the above zipped up together.
Constraint_Optics_Reflection_1.svg.zip
(9.08 KiB) Downloaded 41 times
Jim
User avatar
DeepSOIC
Posts: 6876
Joined: Fri Aug 29, 2014 12:45 am
Location: Saint-Petersburg, Russia

Re: Optical constraints development [Win64 build available]

Postby DeepSOIC » Sun Dec 14, 2014 2:58 pm

Thanks Jim for your work! I'm surprised you actually did it!

First of all, I don't get what the cursor icons are meant for. The constraint itself does not need a mouse cursor (but an xpm is needed for a constraint icon in the 3d view). So, it can be for two things: 1. For a tool that breaks a line in two and applies a refraction law. 2. Autoconstraints. Both are interesting, but I'm not sure I'll do that.

Second, it turned out I don't need the reflection law.

Now, to the essence. Your refraction icons show two interfaces, but the constraint is for just one interface... I don't know... Maybe, for two interfaces, something like a light-through-a-prism would have been more intuitive (think Pink Floyd ;) ). That would have served well for a dropdown-menu icon (the original plan was to have a dropdown with optical constraints), but without a reflection constraint, I don't need a dropdown.

As for the eye on the icon, it is a good idea. But I wouldn't have recognized the eye on your icon if you didn't say that in your message.