Raphael 2 rotate and translate - svg

Here is my script:
<script>
Raphael.fn.polyline = function(pointString) {
return this.path("M" + pointString);
};
window.onload = function() {
var paper = Raphael("holder", 500, 500);
paper.circle(100, 175, 70).attr({"stroke-width":10, "stroke":"red"});
var a = paper.polyline("92,102 96,91 104,91 108,102").attr({"fill":"green", "stroke-opacity":"0"}).rotate(25, 100, 175);
var b = paper.polyline("92,102 96,91 104,91 108,102").attr({"fill":"green", "stroke-opacity":"0"}).rotate(45, 100, 175);
var c = paper.polyline("92,102 96,91 104,91 108,102").attr({"fill":"green", "stroke-opacity":"0"}).rotate(65, 100, 175);
var group = paper.set();
group.push(a, b, c);
group.translate(60);
};
</script>
When I use raphael-1.5.2, the result is:
When I use raphael 2.0, the result is:
In 1.5.2 it uses the rotate transformation to rotate the objects around the circle and in 2.0 it uses the matrix transformation. I assume the matrix transformation transforms the coordinate system for that object, so when you later translate the object in the xy direction it translates it in the xy that is relative for that object.
I need to be able to add green objects around the edge of the red circle and then be able to drag and move everything in the same direction. Am I stuck using 1.5.2 or am I just missing how translate has changed in 2.0?

Use an absolute transform instead of translate. Say you want to move of 100 in x and 50 in y do this:
Element.transform("...T100,50");
Make sure you use a capital T and you'll get an absolute translation. Here's what the documentation says about it:
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.
See documentation
Regarding translate, according to the documentation in Raphael JS 2.0 translate does this:
Adds translation by given amount to the list of transformations of the element.
See documentation
So what happens is it appends a relative transformation based on what was already applied to the object (it basically does "...t100,50").

I suspect that with 1 your transform correctly treats the set as one object but with 2 the little greeny things rotate indepently
Two is a complete redesign so little disconnects like this will occur
Use getBBox and find the centre of your set, then use 1 rotate command on the whole set specifying cx cy derived from getBBox

Related

Ultimate struggle with a full 3d space controller

Sorry if i'm stupid or something, but i having a deep dread from a work on a "full 3d" space movement.
I'm trying to make a "space ship" KinematicBody controller which using basis vectors as a rotation point and have ability to strafe/move left,right,up,down based on it's facing direction.
The issue is i'm having that i want to use a Vector3 as a storage of all input variables, an input strength in particular, but i can't find a convenient way to orient or use this vector's variables to apply it to velocity.
I got a sort of cheap solution which i don't like with applying a rotation to an input vector so it will "corresponds" to one of the basis, but it's starting to brake at some angels.
Could please somebody suggest what i can change in my logic or maybe there is a way to
use quaternion/matrix related methods/formulas?
I'm not sure I fully understand what you want to do, but I can give you something to work with.
I'll assume that you already have the input as a Vector3. If not, you want to see Input.get_action_strength, Input.get_axis and Input.get_vector.
I'm also assuming that the braking situations you encountered are a case of gimbal lock. But since you are asking about applying velocity not rotation, I'll not go into that topic.
Since you are using a KinematicBody, I suppose you would be using move_and_slide or similar method, which work in global space. But you want the input to have to be based on the current orientation. Thus, you would consider your Vector3 which represents the input to be in local space. And the issue is how to go from that local space to the global space that move_and_slide et.al. need.
Transform
You might be familiar with to_local and to_global. Which would interpret the Vector3 as a position:
var global_input_vector:Vector3 = to_global(input_vector)
And the opposite operation would be:
input_vector = to_local(global_input_vector)
The problem with these is that since these consider the Vector3 to be positions, they will translate the vector depending where the KinematicBody is. We can undo that translation:
var global_vec:Vector3 = to_global(local_vec) - global_transform.orign
And the opposite operation would be:
local_vec = to_local(global_vec + global_transform.orign)
By the way this is another way to write the same code:
var global_vec:Vector3 = (global_transform * local_vec) - global_transform.orign
And the opposite operation would be:
local_vec = global_transform.affine_inverse() * (global_vec + global_transform.orign)
Which I'm mentioning because I want you to see the similarity with the following approach.
Basis
I would rather not consider the Vector3 to be positions. Just free vectors. So, we would transform it with only the Basis, like this:
var global_vec:Vector3 = global_transform.basis * local_vec
And the opposite operation would be:
local_vec = global_transform.affine_inverse().basis * global_vec
This approach will not have the translation problem.
You can think of the Basis as a 3 by 3 matrix, and the Transform is that same matrix augmented with a translation vector (origin).
Quat
However, if you only want rotation, let us se quaternions instead:
var global_vec:Vector3 = global_transform.basis.get_rotation_quat() * local_vec
And the opposite operation would be:
local_vec = global_transform.affine_inverse().basis.get_rotation_quat() * global_vec
Well, actually, let us invert just the quaternion:
local_vec = global_transform.basis.get_rotation_quat().inverse() * global_vec
These will only rotate the vector (no scaling, or any other transformation, just rotation) according to the current orientation of the KinematicBody.
Rotating a Transform
If you are trying to rotate a Transform, either…
Do this (quaternion):
transform = Transform(transform.basis * Basis(quaternion), transform.origin)
Or this (quaternion):
transform = transform * Transform(Basis(quaternion), Vector3.ZERO)
Or this (axis-angle):
transform = Transform(transform.basis.rotated(axis, angle), transform.origin)
Or this (axis-angle):
transform = transform * Transform.Identity.rotated(axis, angle)
Or this (Euler angles):
transform = Transform(transform.basis * Basis(pitch, yaw, roll), transform.origin)
Or this (Euler angles):
transform = transform * Transform(Basis(pitch, yaw, roll), Vector3.ZERO)
Avoid this:
transform = transform.rotated(axis, angle)
The reason is that this rotation is always before translation (i.e. this rotates around the global origin instead of the current position), and you will end up with an undesirable result.
And yes, you could use rotate_x, rotate_y and rotate_z, or set rotation of a Spatial. But sometimes you need to work with a Transform directly.
See also:
Godot/Gdscript rotate + translate from local to world space.
How to LERP between 2 angles going the longest route or path in Godot.

d3.svg.line stroke is skewed when scaling y-dimension with SVG transform

Using d3's d3.svg.line produces a line which looks after magnifying only in the y-dimension like this one
Here is the corresponding path element
<path d="M 70.13775,
303.1818181818182 L 73.03775,
285.9090909090909 L 75.93775,
402.5 L 78.83775,
402.5 L 81.73775,
419.77272727272725 L 84.63775,
342.0454545454545 L 87.53775"></path>
As one can see, when the pen is moved to the right, the width of the corresponding line segment is a different one compared to the width of the line of the path segment, when the pen is moved vertically.
Question: Is it possible to draw the line in a such way that the width of line is the same everywhere? As if one draws the line with holding a pen with a round brush perpendicular to the drawing area.
If you want to scale your line along one axis, instead of using an svg transform you would probably be better off using a d3.scale to scale your incoming data when you make your d3.svg.line().
Lets say you have a d3 scale called myScale
Then when you make your d3 svg line, you can use the scale to modify one of the coordinates:
var lineGen = d3.svg.line()
.x(function(d) {return d.x;})
.y(function(d) {return myScale(d.y);});
The solution of using vector-effect will probably give you the result you want in bleeding edge browsers, but it seems like overkill to use an effect to do something this simple, and the lack of browser support for SVG1.2 features might become problematic for you. If you were trying to fix a static svg file that would probably be the way to go, but since you are generating it with d3, you might as well use the built-in methods for scaling.
EDIT
For a simpler solution, you could even scale it by a constant factor:
var scaleFactor = 1.75;
var lineGen = d3.svg.line()
.x(function(d) {return d.x;})
.y(function(d) {return d.y * scaleFactor;});

How can I create a 'getLengthAtPoint()' function for a curved path created via svg/raphaeljs?

I need a way to calculate the length between two points on a curved path created via Raphaeljs. For example, if I have the following path: M10,10T30,50T60,100T80,200T300,400, and I need to know the coordinates of a point that is 150 pixels from that start of the path. The pythagorean theorem cannot be used because the path is curved.
Thanks !
Just call the SVG DOM getPointAtLength method
SVGPoint getPointAtLength(in float distance)
e.g. var point = document.getElementById("pathId").getPointAtLength(150);
OK, here is a possible solution to how to find the distance from the beginning of the path to any one of the points which were used to define it. The idea is to to create a temporary sub path of the original path for each of the points which make it up, and then use 'getToalLength()' to calculate the distance of this sub-path. This distance reflects the distance in the entire original path starting from the first point up to the current point. Now, after the distance has been calculated, it can be stored, and the temporary path can be removed. This way we can calculate and store the distance from the beginning of the original path to each of the points which make it up. Here is the code I use (a bit simplified to focus just on this goal):
var pointsAry = [["M",10,10],["T",30,50],["T",60,100],["T",80,200],["T",300,400]], subPath, path = [];
for (var i = 0 ; i < pointsArray.length ; i++) {
path.push(pointsAry[i]);
subPath = paper.path(path).attr({ "stroke-opacity": 0 }); // make the path invisible
pointsAry[i].subPathSum = subPath.getTotalLength();
subPath.remove();
}
paper is created via Raphaeljs which also supplies the getTotalLength() function. Note the lines are created invisibly because their opacity is 0, and anyhow they are immediately removed.

transition a circle into a line by unrolling it with SVG and d3

For a project we are trying to make a circle into a line (and back again) while it is rotating along a linear path, much like a tire rotates and translates when rolling on a road, or a curled fore finger is extended and recurled into the palm.
In this Fiddle, I have a static SVG (the top circle) that rotates along the linear black path (which is above the circle, to mimic a finger extending) that is defined in the HTML.
I also use d3 to generate a "circle" that is made up of connected points (and can unfurl if you click on/in the circle thanks to #ChrisJamesC here ), and is translated and rotated
in the function moveAlongLine when you click on the purple Line:
function moveAlongLine() {
circle.data([lineData])
.attr("transform", "translate(78.5,0) rotate(-90, 257.08 70) ")
.duration(1000)
circle.on("click", transitionToCircle)
}
The first problem is that the .duration(1000) is not recognized and throws a Uncaught TypeError: Object [object Array] has no method 'duration' in the console, so there is a difference between the static definition of dur in SVG and dynamically setting it in JS/D3, but this is minor.
The other is should the transform attributes be abstracted from one another like in the static circle? in the static circle, the translate is one animation, and the rotation is another, they just have the same star and duration, so they animate together. How would you apply both in d3?
The challenge that I can not get, is how to let it unroll upwards(and also re-roll back), with the static point being the top center of the circle also being the same as the leftmost point on the line.
these seem better:
I should try to get the unfurl animation to occur while also rotating? This seems like it would need to be stepwise/sequential based...
Or Consider an octogon (defined as a path), and if it were to rotate 7 of the sides, then 6, then 5.... Do this for a rather large number of points on a polyhedron? (the circle only needs to be around 50 or so pixels, so 100 points would be more than enough) This is the middle example in the fiddle. Maybe doing this programmatically?
Or This makes me think of a different way: (in the case of the octogon), I could have 8 line paths (with no Z, just an additional closing point), and transition between them? Like this fiddle
Or anything todo with keyframes? I have made an animation in Synfig, but am unsure ho get it to SVG. The synfig file is at http://specialorange.org/filedrop/unroll.sifz if you can convert to SVG, but the xsl file here doesn't correctly convert it for me using xsltproc.
this seems really complicated but potential:
Define a path (likely a bézier curve with the same number of reference points) that the points follow, and have the reference points dynamically translate as well... see this for an concept example
this seems complicated and clunky:
Make a real circle roll by, with a growing mask in front of it, all while a line grows in length
A couple of notes:
The number of points in the d3 circle can be adjusted in the JS, it is currently set low so that you can see a bit of a point in the rendering to verify the rotation has occurred (much like the gradient is in the top circle).
this is to help students learn what is conserved between a number line and a circle, specifically to help learn fractions. For concept application, take a look at compthink.cs.vt.edu:3000 to see our prototype, and this will help with switching representations, to help you get a better idea...
I ended up using the same function that generates the circle as in the question, and did a bit of thinking, and it seemed like I wanted an animation that looked like a finger unrolling like this fiddle. This lead me to the math and idea needed to make it happen in this fiddle.
The answer is an array of arrays, with each nested array being a line in the different state, and then animate by interpolating between the points.
var circleStates = [];
for (i=0; i<totalPoints; i++){
//circle portion
var circleState = $.map(Array(numberOfPoints), function (d, j) {
var x = marginleft + radius + lineDivision*i + radius * Math.sin(2 * j * Math.PI / (numberOfPoints - 1));
var y = margintop + radius - radius * Math.cos(2 * j * Math.PI / (numberOfPoints - 1));
return { x: x, y: y};
})
circleState.splice(numberOfPoints-i);
//line portion
var lineState = $.map(Array(numberOfPoints), function (d, j) {
var x = marginleft + radius + lineDivision*j;
var y = margintop;
return { x: x, y: y};
})
lineState.splice(i);
//together
var individualState = lineState.concat(circleState);
circleStates.push(individualState);
}
and the animation(s)
function all() {
for(i=0; i<numberOfPoints; i++){
circle.data([circleStates[i]])
.transition()
.delay(dur*i)
.duration(dur)
.ease("linear")
.attr('d', pathFunction)
}
}
function reverse() {
for(i=0; i<numberOfPoints; i++){
circle.data([circleStates[numberOfPoints-1-i]])
.transition()
.delay(dur*i)
.duration(dur)
.ease("linear")
.attr('d', pathFunction)
}
}
(Note: This should be in comments but not enough spacing)
Circle Animation
Try the radial wipe from SO. Need to tweak it so angle starts at 180 and ends back at same place (line#4-6,19) and move along the X-axis (line#11) on each interation. Change the <path... attribute to suit your taste.
Line Animation Grow a line from single point to the length (perimeter) of the circle.
Sync both animation so that it appears good on all browsers (major headache!).

How does inkscape calculate the coordinates for control points for "smooth edges"?

I am wondering what algorithm (or formula) Inkscape uses to calculate the control points if the nodes on a path are made "smooth".
That is, if I have a path with five nodes whose d attribute is
M 115.85065,503.57451
49.653441,399.52543
604.56143,683.48319
339.41126,615.97628
264.65997,729.11336
And I change the nodes to smooth, the d attribute is changed to
M 115.85065,503.57451
C 115.85065,503.57451 24.747417,422.50451
49.653441,399.52543 192.62243,267.61777 640.56491,558.55577
604.56143,683.48319 580.13686,768.23328 421.64047,584.07809
339.41126,615.97628 297.27039,632.32348 264.65997,729.11336
264.65997,729.11336
Obviously, Inkscape calculates the control point coordinates (second last and last coordinate pair on lines on or after C). I am interested in the algorithm Inkscape uses for it.
I have found the corresponding piece of code in Inkscape's source tree under
src/ui/tool/node.cpp, method Node::_updateAutoHandles:
void Node::_updateAutoHandles()
{
// Recompute the position of automatic handles.
// For endnodes, retract both handles. (It's only possible to create an end auto node
// through the XML editor.)
if (isEndNode()) {
_front.retract();
_back.retract();
return;
}
// Auto nodes automaticaly adjust their handles to give an appearance of smoothness,
// no matter what their surroundings are.
Geom::Point vec_next = _next()->position() - position();
Geom::Point vec_prev = _prev()->position() - position();
double len_next = vec_next.length(), len_prev = vec_prev.length();
if (len_next > 0 && len_prev > 0) {
// "dir" is an unit vector perpendicular to the bisector of the angle created
// by the previous node, this auto node and the next node.
Geom::Point dir = Geom::unit_vector((len_prev / len_next) * vec_next - vec_prev);
// Handle lengths are equal to 1/3 of the distance from the adjacent node.
_back.setRelativePos(-dir * (len_prev / 3));
_front.setRelativePos(dir * (len_next / 3));
} else {
// If any of the adjacent nodes coincides, retract both handles.
_front.retract();
_back.retract();
}
}
I'm not 100% sure of the quality of this information.
But at least at some point in time for calculating some curves
inkscape seems to have used >>spiro<<.
http://www.levien.com/spiro/
Take a quick look at the page, he's providing a link to his PhD-thesis:
http://www.levien.com/phd/thesis.pdf
in which he's introducing the theory/algorithms ...
Cheers
EDIT:
I'm currently investigating a bit into the matter for a similar purpose, so I stumbled across ...
http://www.w3.org/TR/SVG11/paths.html#PathDataCurveCommands ... the specification of curves for SVG.
So curves, like not circles or arcs, are cubic or quadratic beziers then ...
Have a look at wikipedia for bezier formulas as well:
http://en.wikipedia.org/wiki/B-spline#Uniform_quadratic_B-spline

Resources