Random point inside SVG <path> - svg

The problem is really simple to describe. I have a simple SVG closed shape, like this:
<path d="M435.95,147.99l0.33,0.49l-0.11,1.07l-0.39,0.04l-0.29,-0.15l0.21,-1.4l0.25,-0.05Z"></path>
I want to draw a point at random, somewhere inside this shape.
How to do that? I am hoping for a solution to be as simple as possible.

You could use getBBox to get the bounding box of the path and generate a random point in that range. Then use elementFromPoint with the random point to check that you really are over the shape.
If any elements cover the path then set them to pointer-events="none" so that they are ignored when you do this.

If the path is a convex , we can do it in a simply way:
Raphael.el.getRandomPointInsideConvex=function(){
if(this.type!='path') return undefined;
//sample two points along the path
var len=this.getTotalLength(),
p1=this.getPointAtLength(Math.random()*len),
p2=this.getPointAtLength(Math.random()*len),
ratio=Math.random();
//get the random point
var x=p1.x+(p2.x-p1.x)*ratio,
y=p1.y+(p2.y-p1.y)*ratio;
return {x:x,y:y};
};
You can call the method this way:
//el is an element
var r=el.getRandomPointInsideConvex();
//draw a cross at this point to show it.
el.paper.path(['M',r.x-2,r.y,'L',r.x+2,y,'M',r.x,r.y-2,'L',r.x,r.y+2]);
Hope it helps.

Related

.translated function not working in Godot / best way to change position of bone

I'm working on a program in Godot using Gdscript, and I ran into a problem when trying to use the Transform.translated(Vector3) function. My code is supposed to move a bone to (0,0,0) by translating it by its current coordinates but with negative sign. Example: (1,2,3) would be translated by (-1,-2,-3) so it would end up at (0,0,0). For some reason when I do this, the end position of the bone is not (0,0,0), but some other coordinate. In the Godot documents, it says the .translated function is "relative to the transform's basis vectors", so maybe that's why? Also if there is a better way to change a bones position than using the Transform.translated(Vector3) function that would be helpful too. Thanks!
My Code:
bonePose = skel.get_bone_global_pose(bone)
var globalBonePose = skel.to_global(bonePose.origin)
translateVector = -globalBonePose
var newPose = bonePose.translated(translateVector)
skel.set_bone_pose(bone, newPose)
Code Output / Results:
bonePose (the original position of the bone) is around (-0.82,0.49,0.50)
translateVector (the amount the bone will be translated) is around (0.82,-0.49,-0.50)
newPose (the final position of the bone -- should be [0,0,0]) is around (0.82,-0.66,-0.46). Even when I call skel.to_global(newPose.origin) to see the global coordinates, it's (-0.76,0.44,0.42), which is not (0,0,0)
In Godot a Transform is composed of a basis (a Basis) and an origin (a Vector3). Where the origin handles the translation part of the transform, and the Basis the rest.
A Basis is the set of vectors that define the coordinate system. There is a vector that defines the x axis, another for the y axis, and another for the z axis. And this is the way Godot will encode rotation and scaling transformations.
When the documentation says "relative to the transform's basis vectors" it means the Basis will be applied to the vector you pass in. Thus, in your case, you are getting a translation on the local space of the bone. Which implies that if the bone is rotated or scaled (or something like that), that will affect the translation.
If you don't want to deal with rotation, scaling, et.al. I suggest you work with the origin of the Transform instead.
If you have a Transform and you want another that is otherwise equal but located at (0, 0, 0), you do this:
var new_transform = Transform(transform.basis, Vector.ZERO)
Or replace Vector.ZERO with whatever origin you want to give the new transform.
I also need to remind you that get_bone_global_pose and set_bone_pose do not operate on the same thing. On one hand set_bone_pose is relative to the parent bone, on the other get_bone_global_pose is relative to the Skeleton. Thus, I suggest you use set_bone_global_pose_override instead.
The final piece you need is the opposite of Spatial.to_global. Because setting the pose like as follows…
bonePose = skel.get_bone_global_pose(bone)
var newPose = Transform(bonePose.basis, Vector.ZERO)
skel.set_bone_global_pose_override(bone, newPose, 1.0)
… Would place it at the origin of the Skeleton.
Well, the opposite of Spatial.to_global is Spatial.to_local, and you would use it like this:
bonePose = skel.get_bone_global_pose(bone)
var newPose = Transform(bonePose.basis, skel.to_local(Vector.ZERO))
skel.set_bone_global_pose_override(bone, newPose, 1.0)
Here skel.to_local(Vector.ZERO) should give the origin of the world relative to the Skeleton. And given that set_bone_global_pose_override wants a Transform relative to the Skeleton, the result should be that the bone is placed at the origin of the world. With its rotation and scaling preserved.

How to get global world coordinates of bone in Godot GDscript

I'm writing a program in Godot with GDscript that aims to change the position of multiple bones in an armature. The bone gets translated by a value calculated by the point I want the bone to move to minus the current position of the bone. translateValue = endPoint - currentPoint However, all values must be in world coordinates or global position for the code to work. Godot has various methods to retrieve the bone Transform in order to access the position such as : skeleton.get_bone_pose() , skeleton.get_bone_global_pose , skeleton.get_bone_rest . I tried using skeleton.get_bone_global_pose but it didn't give the global position and seemed to still be relative to something. There's also the to_global() method, but i'm not entirely sure what it does. Could someone explain the differences between these methods and how to get global position? Thanks!
I'll start with these methods:
get_bone_rest
get_bone_custom_pose
get_bone_pose
First of all, get_bone_rest gives you the default transform of the bone, relative to its parent bone. Then the other transform are stacked, in the above order.
Then we have:
get_bone_global_pose
This method gives you the final transform of the bone. And it is relative to the Skeleton. That is, this transform already includes the previously mentioned transforms, combined from parent to child bone.
Thus, converting its result to world space is a matter of composing the transform of the Skeleton:
$Skeleton.global_transform * $Skeleton.get_bone_global_pose(bone_index)
And we have:
get_bone_global_pose_no_override
As the name suggest get_bone_global_pose_no_override ignores any global pose override. That's right, you you can override the global pose. To do that, use set_bone_global_pose_override. See also clear_bones_global_pose_override. These are all, of course, relative to the Skeleton.
The method Spatial.to_global(vector3) is unrelated to the Skeleton. It transforms a vector from the local space of the node on which you call it, to world space. Which might also be useful:
$Skeleton.to_global($Skeleton.get_bone_global_pose(bone_index).origin)

Point of collision between Shapes

I have a problem in with colissions in JavaFX.
First, I detect a collision between a line and a circle using the follow code:
if(line.getBoundsInParent().intersects(circle.getBoundsInParent())){
System.out.println("Collision!");
}
After this, I need catch the coordinate of collision, like the below figure:
How can I catch this coordinate?
Since Line and Circle are both Shapes, you can use the static method intersect in Shape to find their intersection:
Shape collisionArea = Shape.intersect(line, circle)
That collisionArea is a Node as well, so you can use its boundsInParent to find out where to collision took place. Or you could use localToScene or localToScreen to transform local coordinates to scene or screen coordinates if you prefer those.

Raphael JS combine paths

I'm pretty new at SVG and Raphael, but I've been using Illustrator for many years, so I have some assumptions on how it works. I want to combine two paths which should return a single element.
I need to make a speech bubble, but it could be anything really. In this case I tried to make two rect, one with round corners and another square rect which was rotated. It looked alright, but when I tried to move the speech bubble, the rotated element moved in the wrong direction, because of the 45 degree rotation.
How can I compbine paths which I can later manipulate as if it was a single element/path?
Here you go DEMO
var paper = Raphael('canvas',400,400),
r1 = paper.rect(100,100,200,100).attr({fill:'black'}),
r2 = paper.rect(130,130,140,40,5).attr({fill:'white','stroke':'white'}),
r3 = paper.path("M200 170L240 170 220 180z").attr({fill:'white', 'stroke':'white'}),
p = paper.set(r1,r2,r3);
// the rest of the code is in the demo
Note, that it is easier to create triangle via path() and not worry about rotation.
Good Luck ;)
If you mean merging paths like using the Illustrator Pathfinder panel - turning several paths into one path (not a set of paths), merging overlap - I'm pretty sure there's no direct Raphael or SVG equivalent.
The closest thing is, creating a compound path (aka composite path) - the equivalent of cmd-8 or Object > Make Compound Path in Illustrator. This merges paths together into one path, but doesn't remove areas of overlap.
Basically, for a set paper.set( paper.path('M0,0 4,0 0,4z'),paper.path('M9,9 4,9 9,4z') );, an equivalent compound path would be paper.path('M0,0 4,0 0,4z M9,9 4,9 9,4z'); - just joining the path definitions into one, each starting with its own M.
Some differences to Raphael sets:
Less overhead (it's just one complex path, not several separate individual path elements)
Fewer surprises when you move it, sort it, etc:
Things applied to a Raphael set apply to each item in turn, not to the set as a unit - so for example toFront() changes the order within the set, and transforms centre around each item, like Illustrator's transform each, unless you give the transform static co-ordinates.
Things applied to a compound path, however, apply to the whole compound path as one unit.
It's not possible for subpaths of a compound path to have different attributes
Things like gradients apply once across the whole of the compound path, whereas with sets, there will be separate gradients on each separate path
JSBIN demo - compare the gradients, and see how the compound pair is just one path on the DOM.
Here's a simple plugin that adds the ability to take a set and create a compound path from it:
Raphael.st.compoundPath = function(){
var positions = [];
this.forEach( function( element ){
positions.push( element.compoundPath() );
});
return positions.join('');
}
Raphael.el.compoundPath = function(){
var path = this.attr('path');
return path ? Raphael.parsePathString( path ).join('') : '';
}
Then use it like this:
var someSet = paper.set(paper.path('M0,0 4,0 0,4z'),paper.path('M9,9 4,9 9,4z'));
var compPath = paper.path( someSet.compoundPath() );
someSet.remove(); // if you want to replace the set with a compound path
Note that it only combines paths in a set - if you need to combine other shapes with paths, you'll need a way to convert them into paths first.
First thing is that you could push your 2 elements into a Raphael set which you would later move with Element.transform(). This would let you apply the move handler once, and not twice.
Also for your issue, it is acually documented:
... There are also alternative “absolute” translation, rotation and
scale: T, R and S. They will not take previous transformation into
account. For example, ...T100,0 will always move element 100 px
horisontally, while ...t100,0 could move it vertically if there is r90
before. Just compare results of r90t100,0 and r90T100,0. ...

How to transform a path in svg so that it is parallel to its original location?

I have a path defined in SVG. I would like to make two copies of the path and translate them so that one sits parallel to the original on one side, and the other sits parallel on the other side. The idea is to end up with 3 paths, all parallel to each other and not overlapping.
I have tried simple translations such as transform="translate(10,10)" and transform="translate(-10,-10)" for the two paths, but in some paths they end up crossing each other which is not what I want.
Thanks.
Your answer should somewhat work as you've provided it. You might provide more concrete examples of your problem to evoke better solutions.
Your provided commands are going to move the item in two dimensions, not just one.
Also, keep in mind that SVG uses the upper left point as 0,0, and to the right/down are positive. Also check to make sure you're not getting tripped up by units.
If your original path has a bounding box of X,Y then the simplest way to make sure that the copied don't overlap is to translate by +X and -X, so:
translate(-X, 0)
and
translate(X, 0)
where you have computed the value of X and set it in the translate argument.
I'll give you some completely untested code written without looking at the SVG DOM spec. You can then test it and tweak it to get it to work.
First, get the bounding box of an element:
var box = mypath.getBBox();
Then clone the path twice (or make elements):
var rightCopy = mypath.cloneNode(true);
var bottomCopy = mypath.cloneNode(true);
Then transform each copy:
rightCopy.setAttribute("transform", "translate(" + box.width + ",0) " + rightCopy.getAttribute("transform"));
bottomCopy.setAttribute("transform", "translate(0," + box.height + ") " + bottomCopy.getAttribute("transform"));
The reason it looks messy is because the original path might have a transform already on it.
Then add those nodes back into the DOM:
mypath.parentNode.insertBefore(rightCopy, mypath);
mypath.parentNode.insertBefore(bottomCopy, mypath);

Resources