This question already has answers here:
How to deal with floating point number precision in JavaScript?
(47 answers)
Closed 8 years ago.
I have a large amount of numeric values y in javascript. I want to group them by rounding them down to the nearest multiple of x and convert the result to a string.
How do I get around the annoying floating point precision?
For example:
0.2 + 0.4 = 0.6000000000000001
Two things I have tried:
>>> y = 1.23456789
>>> x = 0.2
>>> parseInt(Math.round(Math.floor(y/x))) * x;
1.2000000000000002
and:
>>> y = 1.23456789
>>> x = 0.2
>>> y - (y % x)
1.2000000000000002
From this post: How to deal with floating point number precision in JavaScript?
You have a few options:
Use a special datatype for decimals, like decimal.js
Format your result to some fixed number of significant digits, like this:
(Math.floor(y/x) * x).toFixed(2)
Convert all your numbers to integers
You could do something like this:
> +(Math.floor(y/x)*x).toFixed(15);
1.2
Edit: It would be better to use big.js.
big.js
A small, fast, easy-to-use library for arbitrary-precision decimal arithmetic.
>> bigX = new Big(x)
>> bigY = new Big(y)
>> bigY.div(bigX).round().times(bigX).toNumber() // => 1.2
> var x = 0.1
> var y = 0.2
> var cf = 10
> x * y
0.020000000000000004
> (x * cf) * (y * cf) / (cf * cf)
0.02
Quick solution:
var _cf = (function() {
function _shift(x) {
var parts = x.toString().split('.');
return (parts.length < 2) ? 1 : Math.pow(10, parts[1].length);
}
return function() {
return Array.prototype.reduce.call(arguments, function (prev, next) { return prev === undefined || next === undefined ? undefined : Math.max(prev, _shift (next)); }, -Infinity);
};
})();
Math.a = function () {
var f = _cf.apply(null, arguments); if(f === undefined) return undefined;
function cb(x, y, i, o) { return x + f * y; }
return Array.prototype.reduce.call(arguments, cb, 0) / f;
};
Math.s = function (l,r) { var f = _cf(l,r); return (l * f - r * f) / f; };
Math.m = function () {
var f = _cf.apply(null, arguments);
function cb(x, y, i, o) { return (x*f) * (y*f) / (f * f); }
return Array.prototype.reduce.call(arguments, cb, 1);
};
Math.d = function (l,r) { var f = _cf(l,r); return (l * f) / (r * f); };
> Math.m(0.1, 0.2)
0.02
You can check the full explanation here.
Check out this link.. It helped me a lot.
http://www.w3schools.com/jsref/jsref_toprecision.asp
The toPrecision(no_of_digits_required) function returns a string so don't forget to use the parseFloat() function to convert to decimal point of required precision.
Tackling this task, I'd first find the number of decimal places in x, then round y accordingly. I'd use:
y.toFixed(x.toString().split(".")[1].length);
It should convert x to a string, split it over the decimal point, find the length of the right part, and then y.toFixed(length) should round y based on that length.
Related
I have a simple data table with x and y values, something like this:
x y
-10 -0.505
-9 -0.422
-8 -0.335
-7 -0.243
-6 -0.148
-5 -0.051
-4 0.046
-3 0.144
-2 0.242
-1 0.34
0 0.539
1 0.658
2 0.773
3 0.716
4 0.8
5 0.88
6 0.952
7 1.016
8 1.071
9 1.116
10 1.15
The x step size as well as the min and max values might be different.
I am looking for a built-in functionality to interpolate between these values.
So I need a function which takes the x values and returns the corresponding y value. When there is no exact match, I need the function to linearly interpolate between the two closest values.
Of course I could write my own function but I feel like there might be an easy solution, maybe even built-in in Dart.
I appreciate any help.
Thanks & cheers
Tobi
You can use the SplayTreeMap<double, double> to store your values. The key represents the range to search within.Then use an interpolation function as shown below:
var kEfficiencyMotorsFullLoad = SplayTreeMap<double, double>.from({
0.75: .825,
1.1: .841,
1.5: .853,
2.2: .867,
3.0: .877,
4.0: .886,
5.5: .896,
7.5: .904,
11.0: .914,
15.0: .921,
18.5: .926,
22.0: .930,
30.0: .936,
});
double linearInterpolate(double target, SplayTreeMap<double, double> values) {
if (values.containsKey(target)) return values[target]!;
double? xa = values.lastKeyBefore(target);
double? xb = values.firstKeyAfter(target);
//very small key
if (xa != null && xb == null) return values[xa]!;
//very large key
if (xa == null && xb != null) return values[xb]!;
//strange error
if (xa == null && xb == null)
throw Exception(
"number was not found in the SplayTreeMap, check if it is not empty");
double ya = values[xa] ?? 0;
double yb = values[xb] ?? 0;
return ya + ((yb - ya) * ((target - xa!) / (xb! - xa)));
}
There might be some package on pub.dev that does it already, but I'd use a SplayTreeMap and its lastKeyBefore and firstKeyAfter methods to find the surrounding points and then interpolate between them. For example:
import 'dart:collection' show SplayTreeMap;
import 'dart:math' show Point;
/// Returns the y-coordinate for the specified x-coordinate on the line defined
/// by two given points.
double _interpolate(Point<double> p0, Point<double> p1, double x) {
// y - y0 = m * (x - x0)
var m = (p1.y - p0.y) / (p1.x - p0.x);
return m * (x - p0.x) + p0.y;
}
class InterpolatingMap {
final SplayTreeMap<double, double> _data;
InterpolatingMap(Map<double, double> data)
: _data = SplayTreeMap<double, double>.of(data);
double operator [](double x) {
var value = _data[x];
if (value != null) {
return value;
}
if (_data.isEmpty) {
throw StateError('InterpolatingMap is empty');
}
double? lower = _data.lastKeyBefore(x);
double? upper = _data.firstKeyAfter(x);
assert(lower != null || upper != null);
double x0;
double x1;
if (lower == null) {
// `x` is to the left of the left-most data point. Extrapolate from the
// first two entries.
x0 = upper!;
x1 = _data.firstKeyAfter(upper) ?? x0;
} else if (upper == null) {
// `x` is to the right of the right-most data point. Extrapolate from the
// last two entries.
x1 = lower;
x0 = _data.lastKeyBefore(lower) ?? x1;
} else {
x0 = lower;
x1 = upper;
}
return _interpolate(
Point<double>(x0, _data[x0]!),
Point<double>(x1, _data[x1]!),
x,
);
}
}
void main() {
var interpolatingMap = InterpolatingMap({
0: 1,
1: 2,
2: 1,
});
print(interpolatingMap[-1]); // Prints: 0
print(interpolatingMap[0]); // Prints: 1
print(interpolatingMap[0.25]); // Prints: 1.25
print(interpolatingMap[0.5]); // Prints: 1.5
print(interpolatingMap[0.75]); // Prints: 1.75
print(interpolatingMap[1]); // Prints: 2
print(interpolatingMap[1.5]); // Prints: 1.5
print(interpolatingMap[3]); // Prints: 0
}
Note that InterpolatingMap in the above implementation is a bit of a misnomer since it also will extrapolate values outside the data range. (It should be trivial to make it throw an exception if you want to disable extrapolation, however.) It also doesn't implement the Map interface (which is left as an exercise for readers who care about that).
I would probably use binary search to find the matching range, then interpolate from that.
You can use the lowerBound method from package:collection to find the largest element less then or equal to the element you search for.
Something like:
import"package:collection/collection.dart";
double interpolate(List<num> keyPoints, List<num> values, num x) {
if (keyPoints.length < 2) {
throw ArgumentError.value(keyPoints, "keyPoints",
"Needs at least two points to interpolate");
}
if (keyPoints.length != values.length) {
throw ArgumentError.value(values, "values",
"Must have the same number of elements as the key points");
}
var p = keyPoints.lowerBound(x);
if (p > keyPoints.length - 2) p = keyPoints.length - 2;
var startPosition = keyPoints[p];
var endPosition = keyPoints[p + 1];
var startValue = values[p];
var endValue = values[p + 1];
return (x - startPosition) / (endPosition - startPosition) * (endValue - startValue);
}
This will interpolate the value when x is between two key-points, and extrapolate the first or last range if the x value is outside the key-point range.
I'm working on flutter project using google-maps-flutter plugin, and I want to check if the user location is inside the polygon that I created on the map. There is an easy way using JavaScript api (containsLocation() method) but for flutter I only found a third party plugin,google_map_polyutil, which is only for android and I get a security worming when I run my app. Is there another way to do so??
I found this answer and just modified some minor things to work with dart, I ran a test on a hardcoded polygon. The list _area is my polygon and _polygons is required for my mapcontroller.
final Set<Polygon> _polygons = {};
List<LatLng> _area = [
LatLng(-17.770992200, -63.207739700),
LatLng(-17.776386600, -63.213576200),
LatLng(-17.778348200, -63.213576200),
LatLng(-17.786848100, -63.214262900),
LatLng(-17.798289700, -63.211001300),
LatLng(-17.810547700, -63.200701600),
LatLng(-17.815450600, -63.185252100),
LatLng(-17.816267800, -63.170660900),
LatLng(-17.800741300, -63.153838100),
LatLng(-17.785867400, -63.150919800),
LatLng(-17.770501800, -63.152636400),
LatLng(-17.759712400, -63.160361200),
LatLng(-17.755952300, -63.169802600),
LatLng(-17.752519100, -63.186625400),
LatLng(-17.758404500, -63.195551800),
LatLng(-17.770992200, -63.206538100),
LatLng(-17.770996000, -63.207762500)];
The function ended like this:
bool _checkIfValidMarker(LatLng tap, List<LatLng> vertices) {
int intersectCount = 0;
for (int j = 0; j < vertices.length - 1; j++) {
if (rayCastIntersect(tap, vertices[j], vertices[j + 1])) {
intersectCount++;
}
}
return ((intersectCount % 2) == 1); // odd = inside, even = outside;
}
bool rayCastIntersect(LatLng tap, LatLng vertA, LatLng vertB) {
double aY = vertA.latitude;
double bY = vertB.latitude;
double aX = vertA.longitude;
double bX = vertB.longitude;
double pY = tap.latitude;
double pX = tap.longitude;
if ((aY > pY && bY > pY) || (aY < pY && bY < pY) || (aX < pX && bX < pX)) {
return false; // a and b can't both be above or below pt.y, and a or
// b must be east of pt.x
}
double m = (aY - bY) / (aX - bX); // Rise over run
double bee = (-aX) * m + aY; // y = mx + b
double x = (pY - bee) / m; // algebra is neat!
return x > pX;
}
Notice the polygons property and the onTap method. I was trying to check if the marker created in my map was inside my polygon:
GoogleMap(
initialCameraPosition: CameraPosition(
target: target, //LatLng(0, 0),
zoom: 16,
),
zoomGesturesEnabled: true,
markers: markers,
polygons: _polygons,
onMapCreated: (controller) =>
_mapController = controller,
onTap: (latLng) {
_getAddress(latLng);
},
)
Then i just used the following call in my _getAddress method:
_checkIfValidMarker(latLng, _area);
I hope it helps you to create what you need.
The easiest way to use it - https://pub.dev/packages/maps_toolkit
with isLocationOnPath method.
L. Chi's answer really help.
But due to I have pretty close points, rayCastIntersect might have wrong boolean return if aX is equal to bX
Therefore, I just add aX == bX condition check before calculate m then it works.
bool rayCastIntersect(LatLng tap, LatLng vertA, LatLng vertB) {
double aY = vertA.latitude;
double bY = vertB.latitude;
double aX = vertA.longitude;
double bX = vertB.longitude;
double pY = tap.latitude;
double pX = tap.longitude;
if ((aY > pY && bY > pY) || (aY < pY && bY < pY) || (aX < pX && bX < pX)) {
return false; // a and b can't both be above or below pt.y, and a or
// b must be east of pt.x
}
if (aX == bX) {
return true;
}
double m = (aY - bY) / (aX - bX); // Rise over run
double bee = (-aX) * m + aY; // y = mx + b
double x = (pY - bee) / m; // algebra is neat!
return x > pX;
}
The easiest way to use it - https://pub.dev/packages/maps_toolkit
with PolygonUtil.containsLocation - computes whether the given point lies inside the specified polygon.
G'day,
The function is coded, but it's on the stage frame. I'm looking to get it converted into a more dynamic function so I can just call it on all my textfields.
Here's the code:
function numtolet():void
{
output.text = String(int(earner * 100) / 100);
if (earner >= 1000 && earner < 1000000)
{
output.text = String(int((earner/1000) * 100) / 100 + "k");
}
else if (earner >=1000000 && earner < 1000000000)
{
output.text = String(int((earner/ 1000000) * 100 ) / 100 + " M");
}
}
I'm looking to turn the 'output.text' portion into a variable that changes based on the text field calling the function and 'earner' to the variable the textfield reads.
Cheers,
-Aidan.
You'd better write your function as proper function that can return a String value to assign to a text property or use elsewhere. Also, you should use a pattern that is easily extendable to bigger prefixes, should you need them. Say, I have found a game with a W prefix being used, which is one beyond the common "yotta" prefix, and there was a set of subsequent prefixes as well. So, this is how you should devise such a function:
function numtolet(x:Number):String {
const prefixes:Vector.<String> = Vector.<String>(["","k","m","g","t"]);
// add more to taste. Empty prefix is used if the number is less than 1000
var y:Number=x;
var i:int=1;
// provided x>0, if not, store a minus somewhere and attach later
while((y>=1000) && (i<prefixes.length)) {
y=y/1000;
i++;
}
// there, you have just divided X by 1000 a couple of times and selected the prefix
var s:String = y.toFixed(2)+prefixes[i-1];
// if there was a minus, add it here: s="-"+s;
return s;
}
Then you just call it like this:
output.text=numtolet(earner);
You can do this using the CHANGE event:
output.addEventListener(Event.CHANGE, numtolet);
function numtolet(e:Event):void
{
output.text = String(int(earner * 100) / 100);
if (earner >= 1000 && earner < 1000000)
{
output.text = String(int((earner/1000) * 100) / 100 + "k");
}
else if (earner >=1000000 && earner < 1000000000)
{
output.text = String(int((earner/ 1000000) * 100 ) / 100 + " M");
}
}
This will make the function run every time the text is changed by a user, but you'd probably want to add a few conditional (if)'s to the function, or use a variable to keep track of the curent number. When the number converts to 1k, how does it know what do to at 1000k?
Feel free to ask if you need help on this.
When you use the CHANGE event like Neguido said, and add listeners to different text fields, you can use e.target.text = to change the text in the calling text field.
To target a different variable for each text field is more difficult, because you cant pass extra arguments into the event handlers, and you cant add your own variables/properties to textFields. You could stick each textField into a parent MovieClip and then create variables in there like MovieClip1.earner = 0 and retrieve the values with e.target.parent.earner. You could also write a dynamic extension to the TextField class where you add custom variables. Alternatively you could use a switch statement in your event handler to use different variables for different callers.
Here's a quick function I wrote up for something else. It can easily be adapted to larger numbers by adding another if statement and adding 000 to the number. It also doesn't include the output display, but that can very easily be added as well. Hope it helps!
Call the function via numToLet(earner).
function numToLet(x) {
if (x > 1000000000000000000) {
x = x / 1000000000000000000
x = Number(x.toFixed(2));
return x + "Quin";
}
if (x > 1000000000000000) {
x = x / 1000000000000000
x = Number(x.toFixed(2));
return x + "Quad";
}
if (x > 1000000000000) {
x = x / 1000000000000
x = Number(x.toFixed(2));
return x + "Tril";
}
if (x > 1000000000) {
x = x / 1000000000
x = Number(x.toFixed(2));
return x + "Bil";
}
if (x > 1000000) {
x = x / 1000000
x = Number(x.toFixed(2));
return x + "Mil";
}
if (x < 1000000) {
x = Number(x.toFixed(2));
return x;
}
}
I need to XOR two BitmapData objects together.
I'm writing in Haxe, using the flash.* libraries and the AS3 compile target.
I've investigated HxSL and PixelBender, and neither one seems to have a bitwise XOR operator, nor do they have any other bitwise operators that could be used to create XOR (but am I missing something obvious? I'd accept any answer which gives a way to do a bitwise XOR using only the integer/float operators and functions available in HxSL or PixelBlender).
None of the predefined filters or shaders in Flash that I can find seem to be able to do a XOR of two images (but again, am I missing something obvious? Can XOR be done with a combination of other filters).
I can find nothing like a XOR drawmode for drawing things onto other things (but that doesn't mean it doesn't exist! That would work too, if it exists!)
The only way I can find at the moment is a pixel-by-pixel loop over the image, but this takes a couple of seconds per image even on a fast machine, as opposed to filters, which I use for my other image processing operations, which are about a hundred times faster.
Is there any faster method?
Edit:
Playing around with this a bit more I found that removing the conditional and extra Vector access in the loop speeds it up by about 100ms on my machine.
Here's the previous XOR loop:
// Original Vector XOR code:
for (var i: int = 0; i < len; i++) {
// XOR.
result[i] = vec1[i] ^ vec2[i];
if (ignoreAlpha) {
// Force alpha of FF so we can see the result.
result[i] |= 0xFF000000;
}
}
Here is the updated XOR loop for the Vector solution:
if (ignoreAlpha) {
// Force alpha of FF so we can see the result.
alphaMask = 0xFF000000;
}
// Fewer Vector accessors makes it quicker:
for (var i: int = 0; i < len; i++) {
// XOR.
result[i] = alphaMask | (vec1[i] ^ vec2[i]);
}
Answer:
Here are the solutions that I've tested to XOR two images in Flash.
I found that the PixelBender solution is about 6-10 slower than doing it in straight ActionScript.
I don't know if it's because I have a slow algorithm or it's just the limits of trying to fake bitwise operations in PixelBender.
Results:
PixelBender: ~6500ms
BitmapData.getVector(): ~480-500ms
BitmapData.getPixel32(): ~1200ms
BitmapData.getPixels(): ~1200ms
The clear winner is use BitmapData.getVector() and then XOR the two streams of pixel data.
1. PixelBender solution
This is how I implemented the bitwise XOR in PixelBender, based on the formula given on Wikipedia: http://en.wikipedia.org/wiki/Bitwise_operation#Mathematical_equivalents
Here is a Gist of the final PBK: https://gist.github.com/Coridyn/67a0ff75afaa0163f673
On my machine running an XOR on two 3200x1400 images this takes about 6500-6700ms.
I first converted the formula to JavaScript to check that it was correct:
// Do it for each RGBA channel.
// Each channel is assumed to be 8bits.
function XOR(x, y){
var result = 0;
var bitCount = 8; // log2(x) + 1
for (var n = 0; n < bitCount; n++) {
var pow2 = pow(2, n);
var x1 = mod(floor(x / pow2), 2);
var y1 = mod(floor(y / pow2), 2);
var z1 = mod(x1 + y1, 2);
result += pow2 * z1;
}
console.log('XOR(%s, %s) = %s', x, y, result);
console.log('%s ^ %s = %s', x, y, (x ^ y));
return result;
}
// Split out these functions so it's
// easier to convert to PixelBender.
function mod(x, y){
return x % y;
}
function pow(x, y){
return Math.pow(x, y);
}
function floor(x){
return Math.floor(x);
}
Confirm that it's correct:
// Test the manual XOR is correct.
XOR(255, 85); // 170
XOR(170, 85); // 255
XOR(170, 170); // 0
Then I converted the JavaScript to PixelBender by unrolling the loop using a series of macros:
// Bitwise algorithm was adapted from the "mathematical equivalents" formula on Wikipedia:
// http://en.wikipedia.org/wiki/Bitwise_operation#Mathematical_equivalents
// Macro for 2^n (it needs to be done a lot).
#define POW2(n) pow(2.0, n)
// Slight optimisation for the zeroth case - 2^0 = 1 is redundant so remove it.
#define XOR_i_0(x, y) ( mod( mod(floor(x), 2.0) + mod(floor(y), 2.0), 2.0 ) )
// Calculations for a given "iteration".
#define XOR_i(x, y, i) ( POW2(i) * ( mod( mod(floor(x / POW2(i)), 2.0) + mod(floor(y / POW2(i)), 2.0), 2.0 ) ) )
// Flash doesn't support loops.
// Unroll the loop by defining macros that call the next macro in the sequence.
// Adapted from: http://www.simppa.fi/blog/category/pixelbender/
// http://www.simppa.fi/source/LoopMacros2.pbk
#define XOR_0(x, y) XOR_i_0(x, y)
#define XOR_1(x, y) XOR_i(x, y, 1.0) + XOR_0(x, y)
#define XOR_2(x, y) XOR_i(x, y, 2.0) + XOR_1(x, y)
#define XOR_3(x, y) XOR_i(x, y, 3.0) + XOR_2(x, y)
#define XOR_4(x, y) XOR_i(x, y, 4.0) + XOR_3(x, y)
#define XOR_5(x, y) XOR_i(x, y, 5.0) + XOR_4(x, y)
#define XOR_6(x, y) XOR_i(x, y, 6.0) + XOR_5(x, y)
#define XOR_7(x, y) XOR_i(x, y, 7.0) + XOR_6(x, y)
// Entry point for XOR function.
// This will calculate the XOR the current pixels.
#define XOR(x, y) XOR_7(x, y)
// PixelBender uses floats from 0.0 to 1.0 to represent 0 to 255
// but the bitwise operations above work on ints.
// These macros convert between float and int values.
#define FLOAT_TO_INT(x) float(x) * 255.0
#define INT_TO_FLOAT(x) float(x) / 255.0
XOR for each channel of the current pixel in the evaluatePixel function:
void evaluatePixel()
{
// Acquire the pixel values from both images at the current location.
float4 frontPixel = sampleNearest(inputImage, outCoord());
float4 backPixel = sampleNearest(diffImage, outCoord());
// Set up the output variable - RGBA.
pixel4 result = pixel4(0.0, 0.0, 0.0, 1.0);
// XOR each channel.
result.r = INT_TO_FLOAT ( XOR(FLOAT_TO_INT(frontPixel.r), FLOAT_TO_INT(backPixel.r)) );
result.g = INT_TO_FLOAT ( XOR(FLOAT_TO_INT(frontPixel.g), FLOAT_TO_INT(backPixel.g)) );
result.b = INT_TO_FLOAT ( XOR(FLOAT_TO_INT(frontPixel.b), FLOAT_TO_INT(backPixel.b)) );
// Return the result for this pixel.
dst = result;
}
ActionScript Solutions
2. BitmapData.getVector()
I found the fastest solution is to extract a Vector of pixels from the two images and perform the XOR in ActionScript.
For the same two 3200x1400 this takes about 480-500ms.
package diff
{
import flash.display.Bitmap;
import flash.display.DisplayObject;
import flash.display.IBitmapDrawable;
import flash.display.BitmapData;
import flash.geom.Rectangle;
import flash.utils.ByteArray;
/**
* #author Coridyn
*/
public class BitDiff
{
/**
* Perform a binary diff between two images.
*
* Return the result as a Vector of uints (as used by BitmapData).
*
* #param image1
* #param image2
* #param ignoreAlpha
* #return
*/
public static function diffImages(image1: DisplayObject,
image2: DisplayObject,
ignoreAlpha: Boolean = true): Vector.<uint> {
// For simplicity get the smallest common width and height of the two images
// to perform the XOR.
var w: Number = Math.min(image1.width, image2.width);
var h: Number = Math.min(image1.height, image2.height);
var rect: Rectangle = new Rectangle(0, 0, w, h);
var vec1: Vector.<uint> = BitDiff.getVector(image1, rect);
var vec2: Vector.<uint> = BitDiff.getVector(image2, rect);
var resultVec: Vector.<uint> = BitDiff.diffVectors(vec1, vec2, ignoreAlpha);
return resultVec;
}
/**
* Extract a portion of an image as a Vector of uints.
*
* #param drawable
* #param rect
* #return
*/
public static function getVector(drawable: DisplayObject, rect: Rectangle): Vector.<uint> {
var data: BitmapData = BitDiff.getBitmapData(drawable);
var vec: Vector.<uint> = data.getVector(rect);
data.dispose();
return vec;
}
/**
* Perform a binary diff between two streams of pixel data.
*
* If `ignoreAlpha` is false then will not normalise the
* alpha to make sure the pixels are opaque.
*
* #param vec1
* #param vec2
* #param ignoreAlpha
* #return
*/
public static function diffVectors(vec1: Vector.<uint>,
vec2: Vector.<uint>,
ignoreAlpha: Boolean): Vector.<uint> {
var larger: Vector.<uint> = vec1;
if (vec1.length < vec2.length) {
larger = vec2;
}
var len: Number = Math.min(vec1.length, vec2.length),
result: Vector.<uint> = new Vector.<uint>(len, true);
var alphaMask = 0;
if (ignoreAlpha) {
// Force alpha of FF so we can see the result.
alphaMask = 0xFF000000;
}
// Assume same length.
for (var i: int = 0; i < len; i++) {
// XOR.
result[i] = alphaMask | (vec1[i] ^ vec2[i]);
}
if (vec1.length != vec2.length) {
// Splice the remaining items.
result = result.concat(larger.slice(len));
}
return result;
}
}
}
3. BitmapData.getPixel32()
Your current approach of looping over the BitmapData with BitmapData.getPixel32() gave a similar speed of about 1200ms:
for (var y: int = 0; y < h; y++) {
for (var x: int = 0; x < w; x++) {
sourcePixel = bd1.getPixel32(x, y);
resultPixel = sourcePixel ^ bd2.getPixel(x, y);
result.setPixel32(x, y, resultPixel);
}
}
4. BitmapData.getPixels()
My final test was to try iterating over two ByteArrays of pixel data (very similar to the Vector solution above). This implementation also took about 1200ms:
/**
* Extract a portion of an image as a Vector of uints.
*
* #param drawable
* #param rect
* #return
*/
public static function getByteArray(drawable: DisplayObject, rect: Rectangle): ByteArray {
var data: BitmapData = BitDiff.getBitmapData(drawable);
var pixels: ByteArray = data.getPixels(rect);
data.dispose();
return pixels;
}
/**
* Perform a binary diff between two streams of pixel data.
*
* If `ignoreAlpha` is false then will not normalise the
* alpha to make sure the pixels are opaque.
*
* #param ba1
* #param ba2
* #param ignoreAlpha
* #return
*/
public static function diffByteArrays(ba1: ByteArray,
ba2: ByteArray,
ignoreAlpha: Boolean): ByteArray {
// Reset position to start of array.
ba1.position = 0;
ba2.position = 0;
var larger: ByteArray = ba1;
if (ba1.bytesAvailable < ba2.bytesAvailable) {
larger = ba2;
}
var len: Number = Math.min(ba1.length / 4, ba2.length / 4),
result: ByteArray = new ByteArray();
// Assume same length.
var resultPixel:uint;
for (var i: uint = 0; i < len; i++) {
// XOR.
resultPixel = ba1.readUnsignedInt() ^ ba2.readUnsignedInt();
if (ignoreAlpha) {
// Force alpha of FF so we can see the result.
resultPixel |= 0xFF000000;
}
result.writeUnsignedInt(resultPixel);
}
// Seek back to the start.
result.position = 0;
return result;
}
There are a few possible options depending on what you want to achieve (e.g. is the XOR per channel or is it just any pixel that is non-black?).
There is the BitmapData.compare() method which can give you a lot of information about the two bitmaps. You could BitmapData.threshold() the input data before comparing.
Another option would be to use the draw method with the BlendMode.DIFFERENCE blend mode to draw your two images into the same BitmapData instance. That will show you the difference between the two images (equivalent to the Difference blending mode in Photoshop).
If you need to check if any pixel is non-black then you can try running a BitmapData.threshold first and then draw the result with the difference blend mode as above for the two images.
Are you doing this for image processing or something else like per-pixel hit detection?
To start with I'd have a look at BitmapData and see what is available to play with.
With version 4.7.4 of kineticjs, I was able to use blob.getPoints() to return the x,y values of each point in the blob.
With version 5.0.1 the equivalent - line.points() returns a string of x,y values.
With 4.74 I could determine the max and min bounds easily, however there doesn't seem to be an easy way to do it with 5.0.1
Am I missing something?
line.points() returns 1-d array of coordinates:
[x1, y1, x2, y2, ..., xn, yn]
if you need {x, y} points:
var points = line.points();
for (var i = 0; i < points.length / 2; i++) {
var point = {
x : points[i * 2],
y : points[i * 2 + 1]
};
console.log(point);
};