How to change default unit in Paper.js? - paperjs

I'm using Paper.js (PaperScript) for engineering purposes, so I need all dimensions to be expressed in millimeters. Currently I'm using a conversion function:
function mm2px(mm){ return mm / 25.4 * 96 }
...but it would be nice to write everything in millimeters by default. Is there anyway to achieve this?

There are no unit system in paparjs.
If you would like to use only mm unit, you can do it with view.scaling = 96 / 25.4 in your conversion system.
Ref. http://paperjs.org/reference/view/#scaling.

Related

Calculate distance between two latitude-longitude points with SQLite (almost Haversine formula)

Recently I started a project where I need to calculate the distance between two points given their latitude and longitude and select and order the points by distance.
The logical step to do this is to use the Haversine formula:
Distance = 2 * R * ASIN( SQRT( SIN( (RADIANS(lat1)-RADIANS(lat2))/2 )^2 + COS( RADIANS(lat1) )*COS( RADIANS(lat2) )*SIN( (RADIANS(long1)-RADIANS(long2))/2 )^2 ) )
This is not a problem for MySQL DB, but for some reasons I needed to use SQLITE database and I was building my project with Laravel.
The problem with SQLITE is that has few math functions, and none trigonometric functions (sin, cos, etc.)
At first I thought of using SQLITE extensions, but it seems that PDO that is used by Laravel for DB connections does not allow to load them.
Then I tried PHP createFunction to define functions in SQLite, but, as far as I understand it only works with scalars, that means it does not accept fields names as argument of the defined functions.
I was stucked.
I needed to work with small distances (less than 20km) and I did not need high precision. So a plane geometry was enough for me, but how?
At last, I remembered that sin(angle) ~ angle if angle is small. So I went through the Haversine formula trying to simplify it. It seems a spherical solution of the Pythagorean theorem.
It is done by two parts, the first one defines the difference in latitude, let's say the Y.
Y = R * ABS(RADIANS(lat1)-RADIANS(lat2))
The second part defines the difference in longitude, let's say the X.
X = R * COS(RADIANS(lat0)) * ABS(RADIANS(long1)-RADIANS(long2))
In this part there is a COS since the radius of the circle changes with the latitude. It could be a problem since I said that SQLite does not have that function, but since we are using small variations of the angles lat0 can be a constant value, and calculated once for ever.
Since I have one point given by the user I can put lat0 = lat1 and calculate COS(lat1) before the query or you can define it for your location.
The last thing is to calculate the Estimated_Distance^2 = X^2 + Y^2. Well, SQLite does not even have the SQRT functions, so you must keep it elevated by 2...
The final formula is:
Estimated_Distance = SQRT ( ( R * ABS(RADIANS(lat1)-RADIANS(lat2)) ) ^ 2 + ( R * COS(RADIANS(lat0)) * ABS(RADIANS(long1)-RADIANS(long2)) ) ^ 2 )
The result is not too bad, the error against the Haversine formula is less than 1 m when the distance is less than 10-15 km, but it grows fast with higher distances.
When I will move the project on a production server I'll use MySQL and the correct formula, in the meanwhile this is good enough for me.
If you have any suggestion to improve it, please let me know.
I hope this can help.

is it a bug scaling 0.0-1.0 float to byte by multiplying by 255?

this is something that has always bugged me when I look at code around the web and in so much of the literature: why do we multiply by 255 and not 256?
sometimes you'll see something like this:
float input = some_function(); // returns 0.0 to 1.0
byte output = input * 255.0;
(i'm assuming that there's an implicit floor going on during the type conversion).
am i not correct in thinking that this is clearly wrong?
consider this:
what range of input gives an output of 0 ? (0 -> 1/255], right?
what range of input gives an output of 1 ? (1/255 -> 2/255], great!
what range of input gives an output of 255 ? only 1.0 does. any significantly smaller value of input will return a lower output.
this means that input is not evently mapped onto the output range.
ok. so you might think: ok use a better rounding function:
byte output = round(input * 255.0);
where round() is the usual mathematical rounding to zero decimal places. but this is still wrong. ask the same questions:
what range of input gives an output of 0 ? (0 -> 0.5/255]
what range of input gives an output of 1 ? (0.5/255 -> 1.5/255], twice as much as for 0 !
what range of input gives an output of 255 ? (254.5/255 -> 1.0), again half as much as for 1
so in this case the input range isn't evenly mapped either!
IMHO. the right way to do this mapping is this:
byte output = min(255, input * 256.0);
again:
what range of input gives an output of 0 ? (0 -> 1/256]
what range of input gives an output of 1 ? (1/256 -> 2/256]
what range of input gives an output of 255 ? (255/256 -> 1.0)
all those ranges are the same size and constitute 1/256th of the input.
i guess my question is this: am i right in considering this a bug, and if so, why is this so prevalent in code?
edit: it looks like i need to clarify. i'm not talking about random numbers here or probability. and i'm not talking about colors or hardware at all. i'm talking about converting a float in the range [0,1] evenly to a byte [0,255] so each range in the input that corresponds to each value in the output is the same size.
You are right. Assuming that valueBetween0and1 can take values 0.0 and 1.0, the "correct" way to do it is something like
byteValue = (byte)(min(255, valueBetween0and1 * 256))
Having said that, one could also argue that the desired quality of the software can vary: does it really matter whether you get 16777216 or 16581375 colors in some throw-away plot?
It is one of those "trivial" tasks which is very easy to get wrong by +1/-1. Is it worth it to spend 5 minutes trying to get the 255-th pixel intensity, or can you apply your precious attention elsewhere? It depends on the situation: (byte)(valueBetween0and1 * 255) is a pragmatic solution which is simple, cheap, close enough to the truth, and also immediately, obviously "harmless" in the sense that it definitely won't produce 256 as output. It's not a good solution if you are working on some image manipulation tool like Photoshop or if you are working on some rendering pipeline for a computer game. But it is perfectly acceptable in almost all other contexts. So, whether it is a "bug" or merely a minor improvement proposal depends on the context.
Here is a variant of your problem, which involves random number generators:
Generate random numbers in specified range - various cases (int, float, inclusive, exclusive)
Notice that e.g. Math.random() in Java or Random.NextDouble in C# return values greater or equal to 0, but strictly smaller than 1.0.
You want the case "Integer-B: [min, max)" (inclusive-exclusive) with min = 0 and max = 256.
If you follow the "recipe" Int-B exactly, you obtain the code:
0 + floor(random() * (256 - 0))
If you remove all the zeros, you are left with just
floor(random() * 256)
and you don't need to & with 0xFF, because you never get 256 (as long as your random number generator guarantees to never return 1).
I think your question is misled. It looks like you start assuming that there is some "fairness rule" that enforces the "right way" of translation. Unfortunately in practice this is not the case. If you want just generate a random color, then you may use whatever logic fits you. But if you do actual image processing, there is no rule that says the each integer value has to be mapped on the same interval on the float value. On the contrary what you really want is a mapping between two inclusive intervals [0;1] and [0;255]. And often you don't know how many real discretization steps there will be in the [0;1] range down the line when the color is actually shown. (On modern monitors there are probable all 256 different levels for each color but on other output devices there might be significantly less choices and the total number might be not a power of 2). And the real mapping rule is that if for two colors red component values are R1 and R2 then proportion of the actual colors' red component brightness should be as close to R1:R2 as possible. And this rule automatically implies multiply by 255 when you want to map onto [0;255] and thus this is what everybody does.
Note that what you suggest is most probably introducing a bug rather than fixing a bug. For example the proportion rules actually means that you can calculate a mix of two colors R1 and R2 with mixing coefficients k1 and k2 as
Rmix = (k1*R1 + k2*R2)/(k1+k2)
Now let's try to calculate 3:1 mix of 100% Red with 100% Black (i.e. 0% Red) two ways:
using [0-255] integers Rmix = (255*3+1*0)/(3+1) = 191.25 ≈ 191
using [0;1] floating range and then converting it to [0-255] Rmix_float = (1.0*3 + 1*0.0)/(3+1) = 0.75 so Rmix_converted_256 = 256*0.75 = 192.
It means your "multiply by 256" logic has actually introduced inconsistency of different results depending on which scale you use for image processing. Obviously if you used "multiply by 255" logic as everyone else does, you'd get a consistent answer Rmix_converted_255 = 255*0.75 = 191.25 ≈ 191.

Converting MP3 Duration to Megabytes

If I have an MP3 that has a duration of 3:02 with a bitrate of 192kbps is it possible to get an approximate, or exact, size of the file programatically?
So, taking the 192kbps and multiplying by 182 seconds (3:02) gives
192 x 182 = 34944
Convert that to megabytes and you get 4.26562
In PHP:
($this->duration * $this->bitrate) / 8192;
Is it safe to assume that the approximate filesize of the given MP3 would be 4.2 megabytes?
Yes, you're absolutely right. I even found a forum with a similar discussion ending with the same conclusion. It contains interesting examples : http://www.wjunction.com/5-general-discussion/80348-calculate-mp3-time-length-bitrate-file-size.html
Yes, excluding the metadata. Unless it includes lyrics and a thumbnail, the base estimate should be accurate.

ExtendScript's UnitValue

So I can't find, for the life of me, a clear breakdown of the components of ExtendScript's UnitValue object. Every source I found had something to do with Adobe, and didn't explain it. I'd really like to have a full reference on it, but if no one can find one, I need at least a few questions answered concerning it.
First, what are its constructors? I've seen UnitValue(10,'px') which makes sense, but I've also seen UnitValue(20,20)
Second, how can you convert from one unit to another?
Third, how can you find its value and its unit?
I think I've seen uv.value but nothing getting the unitsLastly, as my tags indicate, this is for Adobe, of course, since I've never seen or heard of any other program that uses ExtendScript.
UnitValue is documented in the Adobe JavaScript Tools Guide.
In particular, you create an object with v = new UnitValue(number, unit), where unit is a string value like in (inch), mm (millimeter), pt (point), px (pixel), etc.
To convert a UnitValue to an actual number, use the as method, e.g. v.as("cm") to convert v into centimeters.
Well, no one else seemed to know, and I finally figured some of it out, so I guess I'll answer it myself:
<This site> was a little helpful as a documentation, but I think Adobe functions slightly different from it.
UnitValue's main constructor is:
UnitValue(numericalvalue,unit)
I've also seen an alternative that accepts one string:
UnitValue("42 in")
For conversion, UnitValue comes with a handy as method which accepts the unit to convert to (as a string), and then returns its measurement in that unit, i.e.:
UnitValue(5,'ft').as('in') === 60
(Note, according to the reference I found, I believe the as method should return the UnitValue instance after being converted to the unit indicated; Adobe's implementation, however, seems to instead merely return the value - therefore I'm use the type-equality operator above to show Adobe's method)
For getting the numerical value and measurement unit, the following two properties exist:
UnitValue.value // number: the numerical value
UnitValue.type // string: the unit of measurement
This is all I could find by my research. If someone has a better answer, post it, and I may accept it.
What's really interesting to me is the baseValue property which allows us to change the frame of reference for the conversion. For instance:
var startUnit = UnitValue(500, "px");
startUnit.baseValue = UnitValue(1 / 72, "in"); // from what I can tell this is the default baseUnit value
$.writeln(v.as("in")); // returns 6.94444444444444 which is what 500px # 72 dpi is as expressed in inches
startUnit.baseValue = UnitValue(1 / 300, "in"); // set to 300dpi
$.writeln(v.as("in")); // returns 1.66666666666667 which is what 500px # 300 dpi is as expressed in inches
I think the default baseValue is always UnitValue(1/72, "in") even if the app.preferences.rulerUnits is set to any other type of measurement but I haven't really looked into it much

Determine true north

I am working on an Arduino device I am building.
I have bought a GPS module and a tilt sensing compas with an accelerometer.
I wish to determine true north so that I can always point an object towards the sun.
Basically I want the device to always find true north wherever it is.
The GPS will give a position, the compass will find magnetic north. I guess the true north can be obtained during movement of the device and written to RAM then retrieved for use when the device is stationary.
But how?
Are you trying to get the most sun for your rotational solar panel? If so then you can get away with just rough position setting between East and West according to your clock (you can improve this with taking long/lat position into the account to calculate sun rise and sun set times). You will need a lot of astronomy calculations if you want to control both azimuth and elevation precisely. Arduino does not support double, and with single you will not have very accurate results (they will be enough for solar panel tracker, but not enough if you want telescope to track some sky object). My advice would be to either investigate a lot on the topic, or take a look at some open source astronomy software and extract the needed calculations from the source (if licence terms permit). Just to give you a hint, this is a small extract from PilotLogic TMoon component that you can get in CodeTyphon/Lazarus/FPC installation package found here:
procedure Sun_Position_Horizontal(date:TdateTime; longitude,latitude: extended; var elevation,azimuth: extended);
var
pos1: T_Coord;
begin
pos1 := sun_coordinate(date);
calc_horizontal(pos1,date,longitude,latitude);
end;
function sun_coordinate(date:TDateTime):t_coord;
var
l,b,r: extended;
lambda,t: extended;
begin
earth_coord(date,l,b,r);
(* convert earth coordinate to sun coordinate *)
l := l+180;
b := -b;
(* conversion to FK5 *)
t := (julian_date(date)-2451545.0)/365250.0*10;
lambda:=l+(-1.397-0.00031*t)*t;
l := l-0.09033/3600;
b := b+0.03916/3600*(cos_d(lambda)-sin_d(lambda));
(* aberration *)
l := l-20.4898/3600/r;
(* correction of nutation - is done inside calc_geocentric *)
{ calc_epsilon_phi(date,delta_phi,epsilon); }
{ l := l+delta_phi; }
(* fill result and convert to geocentric *)
result.longitude := put_in_360(l);
result.latitude := b;
result.radius := r*AU;
calc_geocentric(result,date);
end;
procedure calc_horizontal(var coord:t_coord; date:TDateTime; longitude,latitude: extended);
var
h: extended;
begin
h := put_in_360(star_time(date)-coord.rektaszension-longitude);
coord.azimuth := arctan2_d(sin_d(h), cos_d(h)*sin_d(latitude)-
tan_d(coord.declination)*cos_d(latitude));
coord.elevation := arcsin_d(sin_d(latitude)*sin_d(coord.declination)+
cos_d(latitude)*cos_d(coord.declination)*cos_d(h));
end;
If you had a case that your device is not moving after installation (which is not the case after I reread your question so you can ignore the rest of the message), then your longitude and latitude are fixed and you know them at compile time, or you can enter them manually when device is first installed. That way GPS is not needed. You can also find North once at installation time, so you don't need compass either.
Compass will get haywire when it gets near some magnetic material and will not be practical at all. You can calculate the azimuth and elevation of the sun with respect to your location. It is more practical to use some digital encoders with your system and make calculated incremental movements. A calibrate button on the arduino could be used to normalize the parameters using a standard tools. For fine tune, manual buttons could be provided for up and down movements.

Resources