Paper JS Subtract Paths Result Empty - paperjs

I am new to PaperJs and i am trying to subtract 2 SVG paths.
The html contains two svgs, svg1 and svg2 both of which contain a path.
function SVGPath(elem){
var a = new paper.Path(paper.project.importSVG(elem));
elem.parentNode.removeChild(elem);
return a;
}
window.onload = function() {
paper.setup('canvas');
var svg1 = document.getElementById('svg1')
var path1 = SVGPath(svg1);
path1.fillColor = "red"
path1.position = new paper.Point(0, 0);
var svg2 = document.getElementById('svg2')
var path2 = SVGPath(svg2);
path2.fillColor = 'green'
path2.position = new paper.Point(0, 0);
var result = path1.subtract(path2)
result.position = new paper.Point(10,10)
}
https://jsfiddle.net/820c3sw4/4/
I am trying to subtract the paths, so that the result is then drawn to the canvas.
The exported result appears to be empty of all paths.
<path d="" fill="#008000" fill-rule="nonzero" stroke="none" stroke-width="1" stroke-linecap="butt" stroke-linejoin="miter" stroke-miterlimit="10" stroke-dasharray="" stroke-dashoffset="0" font-family="none" font-weight="none" font-size="none" text-anchor="none" style="mix-blend-mode: normal"></path>
PaperJs docs - http://paperjs.org/reference/path/#subtract-path
Regards,

When you import an SVG node, paperjs try to preserve the document structure of the svg. This means that the top level tag is imported as a Group object and any tags inside it will be imported as nested groups.
You will need to get to the paths inside the nested groups to do the subtraction.
For example:
function SVGPath(elem){
let importedSVG = paper.project.importSVG(elem);
let innerGroup = importedSVG.children[0];
let actualPath = innerGroup.children[0];
elem.parentNode.removeChild(elem);
return actualPath;
}
https://jsfiddle.net/vs3y751m/1/
Also, note that path2, is almost a straight-line with a lot of points in between, but subtraction (also union etc.) only works for paths with an area. So in this case path1 - path2 will just be path1 (similar to arithmetic where a - 0 = a).
subtraction demo

Related

Increment Cell Value by 1 using buttons (g.sheets)

I want to create some small buttons in my google sheet that add or substract the cell value incrementally.
Excuse my artistic abilities (I created the buttons in paint)
You would need to create the increment and decrement functions using Google Apps Script like this:
function increment1() {
var activeCell = SpreadsheetApp.getActiveSpreadsheet().getActiveCell();
var cellValue = activeCell.getValue();
activeCell.setValue(++cellValue);
}
function decrement1() {
var activeCell = SpreadsheetApp.getActiveSpreadsheet().getActiveCell();
var cellValue = activeCell.getValue();
activeCell.setValue(--cellValue);
}
function increment01() {
var activeCell = SpreadsheetApp.getActiveSpreadsheet().getActiveCell();
var cellValue = activeCell.getValue() + 0.1;
activeCell.setValue(cellValue);
}
function decrement01() {
var activeCell = SpreadsheetApp.getActiveSpreadsheet().getActiveCell();
var cellValue = activeCell.getValue() - 0.1;
activeCell.setValue(cellValue);
}
After saving the script, you can draw the buttons using Insert menu -> Drawing, then after you've finished the drawing and placed it onto the sheet, you can right click the drawing, then click on the three dots and select Assign Script:
Then type the function name on the dialog box that appears:
This would increment or decrement the value in the active/selected cell by 1 or 0.1, depending on the entered function.

apply a function over 2 consecutive images in an imageCollection in google earth engine

the function .map applies a function to every individual image in an ImageCollection. And the function .iterate applies a function to one image and the output of the calculation done to the precedent image on an ImageCollection.
The first only works with one image each time, and the second implies modifying each image and utilize it to any calculation with the next one.
I need a function that works like .iterate, but does not modify the precedent image. I just need to do:
image (time -1) / image (time 0).
I can not find a way to do it,
thanks for your help
i have tried,
var first = ee.List([
ee.Image(1).set('system:time_start', time0).select([0], ['pc1'])
]);
var changeDET = function(image, list) {
var previous = ee.Image(ee.List(list).get(-1));
var change = previous.divide(image.select('pc1'))
.set('system:time_start', image.get('system:time_start'));
return ee.List(list).add(change);
};
var cumulative = ee.ImageCollection(ee.List(imageCollection.iterate(changeDET, first)))
.sort('system:time_start', false)
What you can do is to convert your imageCollection into a ee.List object, then map over that list with an index variable to access the previous image. Example code is below:
var length = yourImageCollection.size();
var list = yourImageCollection.toList(length);
var calculated_list = list.map(function(img) {
var index = list.indexOf(img)
img = ee.Image(img);
var previousIndex = ee.Algorithms.If(index.eq(0), index, index.subtract(1));
var previousImage = ee.Image(list.get(previousIndex)):
var change = ee.Image(previousImage.divide(img)
.copyProperties(img, ["system:time_start"]));
return change;
})
I'm not sure what you want to do with the first image, so when map function reach the first image, previousIndex will equal to index. In other words, the first image will be divided by itself (as there is no image before it).
Hope this helps.

Applying blur filter to BitmapData

Here's the code I am using to blur an image using BitmapData. The function is called on a Slider_changeHandler(event:Event):voidevent and the value of the slider is passed to the function as blurvalue.
The problem is the function works but seems to be cummalative (if that's the correct word!), that is, suppose I slide it to the maximum and after that try to reduce the blur by sliding it back towards the front the blur still keeps increasing. How do I make it to work so when I will slide it up blur increases and when I slide it back blur decreases and when slider is at 0, no blur is applied.
var blur:BlurFilter = new BlurFilter();
blur.blurX = blurvalue;
blur.blurY = blurvalue;
blur.quality = BitmapFilterQuality.MEDIUM;
bitmapdata.applyFilter(bitmapdata,new
Rectangle(0,0,bitmapdata.width,bitmapdata.height),new Point(0,0),
blur);
return bitmapdata;
how about returning a clone of the original bitmapData with the filter applied ?
e.g.
var result:BitmapData = bitmapdata.clone();
var blur:BlurFilter = new BlurFilter();
blur.blurX = blurvalue;
blur.blurY = blurvalue;
blur.quality = BitmapFilterQuality.MEDIUM;
result.applyFilter(result,new
Rectangle(0,0,bitmapdata.width,bitmapdata.height),new Point(0,0),blur);
return result;
Also, if you're using the BlurFilter, you might need a larger rectangle, depending on the amount of blur. For that, you can use the generateFilterRect() method to get correct sized rectangle for the filter.
If I were you, I'd take the BitmapData and put it in a Bitmap object, then add the filters:
var bitmap:Bitmap = new Bitmap(bitmapData);
var blur:BlurFilter = new BlurFilter();
blur.blurX = blurvalue;
blur.blurY = blurvalue;
blur.quality = BitmapFilterQuality.MEDIUM;
bitmap.filters = [blur];
By doing this (interchanging the filters array), you're not making the filters cumulative.

localToGlobal not working - for reals though

I know there a bajillion threads on this topic, and maybe I am retarded, but this simply isn't working and I think I am missing something really key?
Lets say I have sprites _testTarget and _testParent nested like this.
_testParent = new Sprite();
this.addChild(_testParent);
_testTarget = new Sprite()
_testParent.addChild(_testParent);
And lets say I want to get the global cords of _testTarget. When I do localToGlobal I always get back 0,0 when I know for a fact its actual cords are like 200,100
var point:Point = new Point(_testTarget.x, _testTarget.y);
point = _testTarget.localToGlobal(point); // returns 0,0
var point:Point = new Point(_testTarget.x, _testTarget.y);
point = _testTarget.parent.localToGlobal(point); // returns 0,0
var point:Point = new Point(this.x, this.y);
point = this.localToGlobal(point); // returns 0,0
var point:Point = new Point(this.x, this.y);
point = this.parent.localToGlobal(point); // Breaks, "parent" is null
If it helps, this class/sprite instantiated inside of a sprite, inside of a sprite, inside of a sprite...etc and the reason its cords are 200,100 are because one of its parent containers is set to that - but I thought localToGlobal was supposed to go all the way to very top layer? Help?
You must have a problem somewhere else (I can't see anyone in the code you pasted, except for the one mentioned by TandemAdam).
This works as expected:
var _testParent:Sprite;
var _testTarget:Sprite;
var _yetAnotherParent:Sprite;
_yetAnotherParent = new Sprite();
this.addChild(_yetAnotherParent);
_testParent = new Sprite();
_yetAnotherParent.addChild(_testParent);
_testTarget = new Sprite()
_testParent.addChild(_testTarget);
_testParent.y = 100;
_yetAnotherParent.y = -500;
var point:Point = new Point(_testTarget.x, _testTarget.y);
point = _testTarget.parent.localToGlobal(point);
trace(point); // (x=0, y=-400)
As a rule of thumb, when translating between coordinate spaces, the object on which you want to call localToGlobal or globalToLocal is almost always the parent of the object you're interested in, because an object's x and y are offsets relative to its parent.
In your first block, this wont work:
_testParent.addChild(_testParent);
Because you can't add a display object as its own child.
This also works as expected -- returns (x=600, y=600). So it looks like there must be something else wrong with your app?
var a:Sprite = new Sprite();
var b:Sprite = new Sprite();
var c:Sprite = new Sprite();
var d:Sprite = new Sprite();
var e:Sprite = new Sprite();
a.x = b.x = c.x = d.x = e.x = 100;
a.y = b.y = c.y = d.y = e.y = 100;
this.addChild(a);
a.addChild(b);
b.addChild(c);
c.addChild(d);
d.addChild(e);
var point:Point = new Point(e.x, e.y);
point = e.localToGlobal(point);
trace(point);
So, props to all you guys suggesting that I look through the rest of my code because it turns out that yes, I am retarded haha. On a hunch (from your advise) I found that the problem had nothing to do with localToGlobal - the problem was that I forgot to wait for the stage to be ready. The solution was very simple:
public function ClassConstructorOrWhatever(){
addEventListener(Event.ADDED_TO_STAGE, handleAddedToStage);
_testParent = new Sprite();
this.addChild(_testParent);
_testTarget = new Sprite()
_testParent.addChild(_testTarget);
}
private function handleAddedToStage(e:Event):void {
var point:Point = new Point(_testTarget .x, _testTarget .y);
point = _testTarget.localToGlobal(point); // RETURNS 200,100!!!! :)
}
So yeah, that was the problem - thanks again guys!

Flex/ActionScript - rotate Sprite around its center

I have created a Sprite in Actionscript and rendered it to a Flex Canvas. Suppose:
var fooShape:Sprite = new FooSpriteSubclass();
fooCanvas.rawChildren.addChild(myshape);
//Sprite shape renders on screen
fooShape.rotation = fooNumber;
This will rotate my shape, but seems to rotate it around the upper-left
point of its parent container(the canvas).
How can I force the Sprite to rotate about is own center point? I could obviously
write code to calculate the rotation, and then have it re-render, but I think there
must be a built-in way to do this, and certainly do not want to 'reinvent the wheel'
if possible.
I am using FlexBuilder, and therefore do not have access to the full Flash API.
Thank you much!
The following steps are required to rotate objects based on a reference point (using Matrix object and getBounds):
Matrix translation (moving to the reference point)
Matrix rotation
Matrix translation (back to original position)
For example to rotate an object 90 degrees around its center:
// Get the matrix of the object
var matrix:Matrix = myObject.transform.matrix;
// Get the rect of the object (to know the dimension)
var rect:Rectangle = myObject.getBounds(parentOfMyObject);
// Translating the desired reference point (in this case, center)
matrix.translate(- (rect.left + (rect.width/2)), - (rect.top + (rect.height/2)));
// Rotation (note: the parameter is in radian)
matrix.rotate((90/180)*Math.PI);
// Translating the object back to the original position.
matrix.translate(rect.left + (rect.width/2), rect.top + (rect.height/2));
Key methods used:
Matrix.rotate
Matrix.translate
DisplayObject.getBounds
Didn't have much luck with the other examples. This one worked for me. I used it on a UIComponent.
http://www.selikoff.net/2010/03/17/solution-to-flex-image-rotation-and-flipping-around-center/
private static function rotateImage(image:Image, degrees:Number):void {
// Calculate rotation and offsets
var radians:Number = degrees * (Math.PI / 180.0);
var offsetWidth:Number = image.contentWidth/2.0;
var offsetHeight:Number = image.contentHeight/2.0;
// Perform rotation
var matrix:Matrix = new Matrix();
matrix.translate(-offsetWidth, -offsetHeight);
matrix.rotate(radians);
matrix.translate(+offsetWidth, +offsetHeight);
matrix.concat(image.transform.matrix);
image.transform.matrix = matrix;
}
Actually I had to add this code to make above solutions work for me.
private var _rotateCount = 0;
var _origginalMatrix:Matrix=new Matrix();
.........
if (_rotateCount++ >= 360 / angleDegrees)
{
myObject.transform.matrix = _origginalMatrix;
_rotateCount = 0;
return;
}
var matrix:Matrix = myObject.transform.matrix;
....
Without that after some long time rotated object slowly moves somewhere right top.
An alternative solution is to put your object inside another View, move it so that your image's center is at the container's top-left corner, and then rotate the container.
import spark.components.*;
var myContainer:View = new View();
var myImage:Image = new Image();
myContainer.addElement(myImage);
myImage.x = myImage.width / -2;
myImage.y = myImage.height / -2;
addElement(myContainer);
myContainer.rotation = whateverAngle;
One issue might be that the width of the image isn't know at the moment it is created, so you might want to find a way around that. (Hardcode it, or see if myImage.preliminaryWidth works)
/**
* Rotates the object based on its center
* Parameters: #obj => the object to rotate
* # rotation => angle to rotate
* */
public function RotateAroundCenter(obj:Object, rotation:Number):void
{
var bound:Rectangle = new Rectangle();
// get the bounded rectangle of objects
bound = obj.getRect(this);
// calculate mid poits
var midx1:Number = bound.x + bound.width/2;
var midy1:Number = bound.y + bound.height/2;
// assign the rotation
obj.rotation = rotation;
// assign the previous mid point as (x,y)
obj.x = midx1;
obj.y = midy1;
// get the new bounded rectangle of objects
bound = obj.getRect(this);
// calculate new mid points
var midx2:Number = bound.x + bound.width/2;
var midy2:Number = bound.y + bound.height/2;
// calculate differnece between the current mid and (x,y) and subtract
//it to position the object in the previous bound.
var diff:Number = midx2 - obj.x;
obj.x -= diff;
diff = midy2 - obj.y;
obj.y -= diff;
}
//////////////////
Usage:
you can use the above function as described below,
var img:Canvas = new Canvas()
RotateAroundCenter(img, rotation);
This will help you
REf: http://subashflash.blogspot.in/2010/08/rotation-of-object-based-on-center.html
If you want to rotate around the center, merely center the asset inside your sprite by setting the internal assets x and y to half of the width and height of the asset. This swill center your content and allow it to rotate around a center point.
An example of runtime loaded assets is as follows:
var loader:Loader = new Loader():
var request:URLRequest = new URLRequest(path/to/asset.ext);
loader.contentLoaderInfo.addEventListener(Event.COMPLETE, _onLoaderComplete);
loader.load(request);
private function _onLoaderComplete(e:Event):void
{
var mc:MovieClip = e.target.content as MovieClip;
mc.x = -mc.width * 0.5;
mc.y = -mc.height * 0.5;
mc.rotation = 90;
addChild(mc);
}

Resources