Hi I need help finding coordinate or points offset from two endpoints of a line. In my program, I would like to specify the two points and the offset. Then I need to calculate the two offset coordinates.
I worked something out using trigonometry but it only works in some cases and when the line is in the positive quadrant.
Here is an image describing what I need to find:
Points on line
Ok so I need to find X3,Y3 and X4,Y4 coordinates.
My method I followed:
Calculate angle:
Ang = atan((Y2 - Y1)/(X2 - X1))
To find X3:
X3 = X1 + Offset * Cos(Ang)
The same concept for Y3
The issue is that if the line is in a different quadrant the point info is not correct... Any help, please.
This question is a clear case for using 2d vector math. The idea is that we subtract p1 from p2 to give us a vector that describes the length and direction of the line. We then normalize this vector, such that it has a length of 1. If you then multiply this normalized vector with the number of units you'd like to move away from the end and add the result to the end-point, you'll have a new point.
Consider an example walking along the x axis:
p1 = 0,0
p2 = 10,0
dif = p2 - p1 = (10,0)
length is 10, so it's 10 times too long - we divide it by 10 to get a vector 1 unit long.
If we then move 5 times (1,0), we end up at 5,0 - 5 units away, bewdy!
Here's a function that achieves the same thing:
function calcOffsetPoint(x1,y1, x2,y2, distTowardsP2fromP1)
{
var p1 = new vec2d(x1,y1);
var p2 = new vec2d(x2,y2);
var delta = p2.sub(p1);
var dirVec = delta.clone();
dirVec.normalize();
dirVec.timesEquals(distTowardsP2fromP1);
var resultPoint = p1.add(dirVec);
return resultPoint;
}
As you can see, this makes use of something I've called vec2d. There's a copy of it in the following snippet:
"use strict";
function byId(id){return document.getElemetById(id)}
function newEl(tag){return document.createElement(tag)}
window.addEventListener('load', onDocLoaded, false);
function onDocLoaded(evt)
{
var end1 = new vec2d(0,0);
var end2 = new vec2d(10,0);
var midPoint = calcOffsetPoint(end1.x,end1.y, end2.x,end2.y, 5);
console.log( midPoint.toStringN(2) );
}
class vec2d
{
constructor(x=0, y=0)
{
this.mX = x;
this.mY = y;
}
get x(){return this.mX;}
set x(newX){this.mX = newX;}
get y(){return this.mY;}
set y(newY){this.mY = newY;}
add(other)
{
return new vec2d(this.x+other.x, this.y+other.y);
}
sub(other)
{
return new vec2d(this.x-other.x, this.y-other.y);
}
timesEquals(scalar)
{
this.x *= scalar;
this.y *= scalar;
return this;
}
divByEquals(scalar)
{
this.x /= scalar;
this.y /= scalar;
return this;
}
dotProd(other)
{
return this.x*other.x + this.y*other.y;
}
length()
{
return Math.hypot(this.x, this.y);
}
normalize()
{
this.divByEquals( this.length() );
return this;
}
perpendicular()
{
var tmp = this.x;
this.x = -this.y;
this.y = tmp;
return this;
}
clone()
{
return vec2d.clone(this);
}
static clone(other)
{
return new vec2d(other.x, other.y);
}
toString(){return `vec2d {x: ${this.x}, y: ${this.y}}`}
toStringN(n){return `vec2d {x: ${this.x.toFixed(n)}, y: ${this.y.toFixed(n)}}`}
}
function calcOffsetPoint(x1,y1, x2,y2, distTowardsP2fromP1)
{
var p1 = new vec2d(x1,y1);
var p2 = new vec2d(x2,y2);
var delta = p2.sub(p1);
var dirVec = delta.clone();
dirVec.normalize();
dirVec.timesEquals(distTowardsP2fromP1);
var resultPoint = p1.add(dirVec);
return resultPoint;
}
I had some spare time over the weekend, so put together a working demo of the image you posted. Have a play around. Make sure you run it in full-screen, so you can see the sliders that set the offsets for p3 and p4. Disregard the coordinate-system transformation stuff, that's just there to allow me to make an image the same dimensions as your image yet conveniently display it in a window with about 5% the area. The questions come from the exercise section of some old text-book I was reading over the weekend.
"use strict";
class vec2d
{
constructor(x=0,y=0)
{
this.x = x;
this.y = y;
}
abs()
{
this.x = Math.abs(this.x);
this.y = Math.abs(this.y);
return this;
}
add(vec1)
{
return new vec2d(this.x+vec1.x, this.y+vec1.y);
}
sub(vec1)
{
return new vec2d(this.x-vec1.x, this.y-vec1.y);
}
mul(scalar)
{
return new vec2d(this.x*scalar, this.y*scalar);
}
plusEquals(vec1)
{
this.x += vec1.x;
this.y += vec1.y;
return this;
}
minusEquals(vec1)
{
this.x -= vec1.x;
this.y -= vec1.y;
return this;
}
timesEquals(scalar)
{
this.x *= scalar;
this.y *= scalar;
return this;
}
divByEquals(scalar)
{
this.x /= scalar;
this.y /= scalar;
return this;
}
normalize()
{
var len = this.length;
this.x /= len;
this.y /= len;
return this;
}
get length()
{
//return Math.sqrt( (this.x*this.x)+(this.y*this.y) );
return Math.hypot( this.x, this.y );
}
set length(newLen)
{
var invLen = newLen / this.length;
this.timesEquals(invLen);
}
dotProd(vec1)
{
return this.x*vec1.x + this.y*vec1.y;
}
perp()
{
var tmp = this.x;
this.x = -this.y;
this.y = tmp;
return this;
}
wedge(other)
{ // computes an area for parallelograms
return this.x*other.y - this.y*other.x;
}
static clone(other)
{
var result = new vec2d(other.x, other.y);
return result;
}
clone() // clone self
{
return vec2d.clone(this);
}
setTo(other)
{
this.x = other.x;
this.y = other.y;
}
get(){ return {x:this.x, y:this.y}; }
toString(){ return `vec2d {x: ${this.x}, y: ${this.y}}` }
toStringN(n){ return `vec2d {x: ${this.x.toFixed(n)}, y: ${this.y.toFixed(n)}}` }
print(){console.log(this.toString())}
};
class mat3
{
static clone(other)
{
var result = new mat3();
other.elems.forEach(
function(el, index, collection)
{
result.elems[index] = el;
}
);
return result;
}
clone()
{
return mat3.clone(this);
}
constructor(a,b,c,d,e,f)
{
if (arguments.length < 6)
this.setIdentity();
else
this.elems = [a,b,0,c,d,0,e,f,1];
}
setIdentity()
{
this.elems = [1,0,0, 0,1,0, 0,0,1];
}
multiply(other, shouldPrepend)
{
var a, b, c = new mat3();
if (shouldPrepend === true)
{
a = other;
b = this;
}
else
{
a = this;
b = other;
}
c.elems[0] = a.elems[0]*b.elems[0] + a.elems[1]*b.elems[3] + a.elems[2]*b.elems[6];
c.elems[1] = a.elems[0]*b.elems[1] + a.elems[1]*b.elems[4] + a.elems[2]*b.elems[7];
c.elems[2] = a.elems[0]*b.elems[2] + a.elems[1]*b.elems[5] + a.elems[2]*b.elems[8];
// row 1
c.elems[3] = a.elems[3]*b.elems[0] + a.elems[4]*b.elems[3] + a.elems[5]*b.elems[6];
c.elems[4] = a.elems[3]*b.elems[1] + a.elems[4]*b.elems[4] + a.elems[5]*b.elems[7];
c.elems[5] = a.elems[3]*b.elems[2] + a.elems[4]*b.elems[5] + a.elems[5]*b.elems[8];
// row 2
c.elems[6] = a.elems[6]*b.elems[0] + a.elems[7]*b.elems[3] + a.elems[8]*b.elems[6];
c.elems[7] = a.elems[6]*b.elems[1] + a.elems[7]*b.elems[4] + a.elems[8]*b.elems[7];
c.elems[8] = a.elems[6]*b.elems[2] + a.elems[7]*b.elems[5] + a.elems[8]*b.elems[8];
for (var i=0; i<9; i++)
this.elems[i] = c.elems[i];
}
transformVec2s(pointList)
{
var i, n = pointList.length;
for (i=0; i<n; i++)
{
var x = pointList[i].x*this.elems[0] + pointList[i].y*this.elems[3] + this.elems[6];
var y = pointList[i].x*this.elems[1] + pointList[i].y*this.elems[4] + this.elems[7];
pointList[i].x = x;
pointList[i].y = y;
}
}
makeTransformedPoints(pointList)
{
var result = [];
for (var i=0,n=pointList.length;i<n;i++)
{
var x = pointList[i].x*this.elems[0] + pointList[i].y*this.elems[3] + this.elems[6];
var y = pointList[i].x*this.elems[1] + pointList[i].y*this.elems[4] + this.elems[7];
result.push( new vec2d(x,y) );
}
return result;
}
rotate(degrees, shouldPrepend)
{
var tmp = new mat3();
tmp.elems[0] = Math.cos( degrees/180.0 * Math.PI );
tmp.elems[1] = -Math.sin( degrees/180.0 * Math.PI );
tmp.elems[3] = -tmp.elems[1];
tmp.elems[4] = tmp.elems[0];
this.multiply(tmp, shouldPrepend);
}
scaleEach(scaleX, scaleY, shouldPrepend)
{
var tmp = new mat3();
tmp.elems[0] = scaleX;
tmp.elems[4] = scaleY;
this.multiply(tmp, shouldPrepend);
}
scaleBoth(scaleAmount, shouldPrepend)
{
var tmp = new mat3();
tmp.elems[0] = scaleAmount;
tmp.elems[4] = scaleAmount;
this.multiply(tmp, shouldPrepend);
}
translate(transX, transY, shouldPrepend)
{
var tmp = new mat3();
tmp.elems[6] = transX;
tmp.elems[7] = transY;
this.multiply(tmp, shouldPrepend);
}
determinant()
{
var result, a, b;
a = ( (this.elems[0]*this.elems[4]*this.elems[8])
+ (this.elems[1]*this.elems[5]*this.elems[6])
+ (this.elems[2]*this.elems[3]*this.elems[7]) );
b = ( (this.elems[2]*this.elems[4]+this.elems[6])
+ (this.elems[1]*this.elems[3]+this.elems[8])
+ (this.elems[0]*this.elems[5]+this.elems[7]) );
result = a - b;
return result;
}
isInvertible()
{
return (this.determinant() != 0);
}
invert()
{
var det = this.determinant();
if (det == 0)
return;
var a,b,c,d,e,f,g,h,i;
a = this.elems[0]; b = this.elems[1]; c = this.elems[2];
d = this.elems[3]; e = this.elems[4]; f = this.elems[5];
g = this.elems[6]; h = this.elems[7]; i = this.elems[8];
this.elems[0] = (e*i - f*h); this.elems[1] = -((b*i) - (c*h)); this.elems[2] = (b*f)-(c*e);
this.elems[3] = -(d*i - f*g); this.elems[4] = (a*i) - (c*g); this.elems[5] = -( (a*f) - (c*d) );
this.elems[6] = (d*h - e*g); this.elems[7] = -((a*h) - (b*g)); this.elems[8] = (a*e)-(b*d);
var detInv = 1.0 / det;
for (var i=0; i<9; i++)
this.elems[i] *= detInv;
return this;
}
reset()
{
this.setIdentity();
}
print()
{
var str = '';
for (var i=0; i<9; i++)
{
if (i && i%3==0)
str += "\n";
str += " " + this.elems[i].toFixed(5);
}
console.log(str);
}
}
function byId(id){return document.getElementById(id)}
function newEl(tag){return document.createElement(tag)}
window.addEventListener('load', onDocLoaded, false);
function onDocLoaded(evt)
{
byId('output').addEventListener('mousemove', onMouseMove, false);
byId('slider1').addEventListener('input', onSliderInput, false);
byId('slider2').addEventListener('input', onSliderInput, false);
draw();
}
//(400-48)/400 = 0.88
var invMat, svgInvMat;
function onMouseMove(evt)
{
var mousePos = new vec2d(evt.offsetX,evt.offsetY);
var worldPos = mousePos.clone();
invMat.transformVec2s( [worldPos] );
byId('screenMouse').textContent = `screen: ${mousePos.x},${mousePos.y}`;
byId('worldMouse').textContent = `world: ${worldPos.x.toFixed(1)}, ${worldPos.y.toFixed(1)}`;
}
function onSliderInput(evt)
{
draw();
}
function updateSliderLabels()
{
byId('ofset1Output').textContent = byId('slider1').value;
byId('ofset2Output').textContent = byId('slider2').value;
}
function draw()
{
var can = byId('output');
var ctx = can.getContext('2d');
ctx.clearRect(0,0,can.width,can.height);
var orientMat = evaluateViewOrientationMatrix(0.06*can.width,can.height-24, 0,-1);
var scaleMat = computeWindowToViewPortMatrix(2052,1317, can.width,can.height);
var viewMat = scaleMat.clone();
viewMat.multiply(orientMat);
console.log('viewMat');
viewMat.print();
invMat = viewMat.clone().invert();
for (var i=0; i<9; i++)
invMat.elems[i] /= invMat.elems[8];
ctx.strokeStyle = '#fff';
var axisPts = [ new vec2d(0,1070), new vec2d(0,0), new vec2d(0.88*2052,0) ]; // xAxis line 88% of image width
var axis = viewMat.makeTransformedPoints(axisPts);
drawLine(axis[0].x,axis[0].y, axis[1].x,axis[1].y, ctx);
drawLine(axis[1].x,axis[1].y, axis[2].x,axis[2].y, ctx);
var lineEnds = [new vec2d(330,263), new vec2d(1455,809)];
var pts2 = viewMat.makeTransformedPoints(lineEnds);
drawCircle(pts2[0].x,pts2[0].y, 4, ctx);
drawCircle(pts2[1].x,pts2[1].y, 4, ctx);
drawLine(pts2[0].x,pts2[0].y, pts2[1].x,pts2[1].y, ctx);
var rawP3 = calcOffsetCoords(lineEnds[0].x,lineEnds[0].y, lineEnds[1].x,lineEnds[1].y, byId('slider1').value);
var rawP4 = calcOffsetCoords(lineEnds[1].x,lineEnds[1].y, lineEnds[0].x,lineEnds[0].y, byId('slider2').value);
var ofsPts = viewMat.makeTransformedPoints( [rawP3, rawP4] );
drawCircle(ofsPts[0].x,ofsPts[0].y, 4, ctx);
drawCircle(ofsPts[1].x,ofsPts[1].y, 4, ctx);
updateSliderLabels();
}
function calcOffsetCoords(x1,y1, x2,y2, offset)
{
var dx = x2 - x1;
var dy = y2 - y1;
var lineLen = Math.hypot(dx, dy);
var normDx=0, normDy=0;
if (lineLen != 0)
{
normDx = dx / lineLen;
normDy = dy / lineLen;
}
var resultX = x1 + (offset * normDx);
var resultY = y1 + (offset * normDy);
return {x:resultX,y:resultY};//new vec2d(resultX,resultY); //{x:resultX,y:resultY};
}
// Exercise 6-1:
// Write a procedure to implement the evaluateViewOrientationMatrix function that calculates the elements of the
// matrix for transforming world coordinates to viewing coordinates, given the viewing coordinate origin Porigin and
// the viewUp vector
function evalViewOrientMatrix(screenOriginX,screenOriginY, worldUpVectorX,worldUpVectorY)
{
var worldUp = {x: worldUpVectorX, y: worldUpVectorY};
var len = Math.hypot(worldUp.x, worldUp.y);
if (len != 0)
len = 1.0 / len;
worldUp.x *= len;
worldUp.y *= len;
var worldRight = {x: worldUp.y, y: -worldUp.x};
var rotMat = svg.createSVGMatrix();
rotMat.a = worldRight.x;
rotMat.b = worldRight.y;
rotMat.c = worldUp.x;
rotMat.d = worldUp.y;
var transMat = svg.createSVGMatrix();
transMat = transMat.translate(screenOriginX, screenOriginY);
var result = rotMat.multiply(transMat);
return result;
}
function evaluateViewOrientationMatrix(screenOriginX,screenOriginY, worldUpVectorX,worldUpVectorY)
{
var worldUp = new vec2d(worldUpVectorX, worldUpVectorY);
worldUp.normalize();
var worldRight = worldUp.clone().perp();
var rotMat = new mat3();
rotMat.elems[0] = worldRight.x; rotMat.elems[1] = worldRight.y;
rotMat.elems[3] = worldUp.x; rotMat.elems[4] = worldUp.y;
var transMat = new mat3();
transMat.translate(screenOriginX,screenOriginY);
var result = rotMat.clone();
result.multiply(transMat);
return result;
}
/*
0 1 2
3 4 5
6 7 8
translation
-----------
1 0 0
0 1 0
tX tY 1
scaling
---------
sX 0 0
0 sY 0
0 0 1
rotation
--------
cosX -sinX 0
sinX cosX 0
0 0 1
*/
// Exercise 6-2:
// Derive the window to viewport transformation equations 6-3 by first scaling the window to
// the size of the viewport and then translating the scaled window to the viewport position
function computeWindowToViewPortMatrix(windowWidth,windowHeight,viewPortWidth,viewPortHeight)
{
var result = new mat3();
result.scaleEach(viewPortWidth/windowWidth,viewPortHeight/windowHeight);
return result;
}
// returns an SVGMatrix
function compWnd2ViewMat(windowWidth,windowHeight,viewPortWidth,viewPortHeight)
{
var result = svg.createSVGMatrix();
return result.scaleNonUniform(viewPortWidth/windowWidth,viewPortHeight/windowHeight);
}
function drawLine(x1,y1,x2,y2,ctx)
{
ctx.beginPath();
ctx.moveTo(x1,y1);
ctx.lineTo(x2,y2);
ctx.stroke();
}
function drawCircle(x,y,radius,ctx)
{
ctx.beginPath();
ctx.arc(x, y, radius, 0, (Math.PI/180)*360, false);
ctx.stroke();
ctx.closePath();
}
canvas
{
background-color: black;
}
.container
{
display: inline-block;
background-color: #888;
border: solid 4px #555;
}
#screenMouse, #worldMouse, .control
{
display: inline-block;
width: calc(513px/2 - 2*8px);
margin-left: 8px;
}
<body>
<div class='container'>
<canvas id='output' width='513' height='329'></canvas><br>
<div id='screenMouse'></div><div id='worldMouse'></div>
<div>
<div class='control'>P2 ofs: <input id='slider1' type='range' min='0' max='500' value='301'><span id='ofset1Output'></span></div>
<div class='control'>P3 ofs: <input id='slider2' type='range' min='0' max='500' value='285'><span id='ofset2Output'></span></div>
</div>
</div>
</body>
Here is the Script i'm using to stream my tumblr blog posts to my website, i have the correct API Key, and Base host name, still nothing appears. Is there some other information I'm bypassing ? any help will be greatly appreciated.
<script type="text/javascript">
var $_api_key = 'PhLtoFx1aCBtu9IG3pIuT9BPd0Vxb602nPZtdMKxHvHM89VH28',
$_base_hostname = 'http://amongtheprimeblog.tumblr.com',
$_full_width = 1170;
$_rows = 2
$_cols = 3;
$_min_width = $_full_width / $_cols,
$_nsfw_tag = 'nsfw';
$_display_limit = $_rows * $_cols,
$_post_limit = $_display_limit * 2,
$_photos_api = 'https://api.tumblr.com/v2/blog/'+$_base_hostname+'/posts/photo?limit='+$_post_limit+'&api_key='+$_api_key,
jQuery.ajax($_photos_api,
{
dataType: 'jsonp',
success: function ($_posts) {
//console.log($_posts);
var $_photos = [],
$_displayed = 0 ;
for(var i=0; i < $_post_limit; i++) {
var $_post_url = $_posts.response.posts[i].post_url.replace('http://','https://'),
$_tag_count = $_posts.response.posts[i].tags.length,
$_photo_count = $_posts.response.posts[i].photos[0].alt_sizes.length,
$_post_photo_big = $_posts.response.posts[i].photos[0].original_size.url.replace('http://','https://'),
$_post_photo_big_width = $_posts.response.posts[i].photos[0].original_size.width,
$_post_photo_big_height = $_posts.response.posts[i].photos[0].original_size.height,
$_can_display = true;
// Check NSFW to keep Adroll happy!
for (var k=0; k < $_tag_count; k++ ){
if($_posts.response.posts[i].tags[k] == $_nsfw_tag) {
$_can_display = false;
}
}
// Iterate for most suitable image size.
if($_can_display) {
for (var j=0; j < $_photo_count; j++ ) {
if($_posts.response.posts[i].photos[0].alt_sizes[j].width > $_min_width) {
$_post_photo = $_posts.response.posts[i].photos[0].alt_sizes[j].url.replace('http://','https://');
} else {
break;
}
}
$_photos.push('<a id="tumblr_'+i+'" class="tumblr_post" href="'+$_post_url+'" target="_blank" data-src-big="'+$_post_photo_big+'" data-src-big-width="'+$_post_photo_big_width+'" data-src-big-height="'+$_post_photo_big_height+'"><img src="'+$_post_photo+'"/></a>');
$_displayed++;
if( $_displayed == $_display_limit) {
break;
}
}
}
jQuery('#tumblr_images').html($_photos.join(''));
},
}
);
function loadTumblrModal(id) {
var $_post = jQuery('#'+id),
$_post_next = $_post.next('.tumblr_post').attr('id'),
$_post_prev = $_post.prev('.tumblr_post').attr('id'),
$_post_link = $_post.attr('href'),
$_modal = jQuery('#tumblrModal'),
$_post_photo_src = $_post.attr('data-src-big').replace('http://','https://'),
$_post_photo_height = parseInt($_post.attr('data-src-big-height')),
$_post_photo_width = parseInt($_post.attr('data-src-big-width')),
$_post_photo_ratio = $_post_photo_width / $_post_photo_height,
$_window_height = jQuery(window).height(),
$_dialog_padding = 20,
$_dialog_margin = 20,
$_dialog_height = jQuery(window).height() - ($_dialog_margin * 2),
$_follow_iframe = '<iframe class="follow-button " src="https://platform.tumblr.com/v1/follow_button.html?button_type=1&tumblelog=theiloveuglyblog&color_scheme=dark" frameborder="0" scrolling="no" width="118" height="25"></iframe>';
// Re-Calibrate Dialog if Image is smaller than Window
if($_post_photo_height < $_dialog_height) {
$_dialog_height = $_post_photo_height;
}
// Set Dialog & Image Dimensions
var $_image_height = $_dialog_height - ($_dialog_padding *2),
$_image_width = $_image_height * $_post_photo_ratio,
$_dialog_width = $_image_width + ($_dialog_padding * 2);
// Force First/Last if Undefined for Next/Prev. Creates looping
if(typeof $_post_next === 'undefined') {
$_post_next = $_post.parent().find('.tumblr_post').first().attr('id');
}
if(typeof $_post_prev === 'undefined') {
$_post_prev = $_post.parent().find('.tumblr_post').last().attr('id');
}
// FireUp all the Modal
$_modal.find('.modal-dialog').css({
"width" : $_dialog_width + 'px',
"height" : $_dialog_height + 'px',
"margin-left" : -($_dialog_width/2) + 'px',
"margin-top" : -($_dialog_height/2) + 'px',
});
$_modal.find('.tumblr_img').html('<img src="'+$_post_photo_src+'" width="'+$_image_width+'" height="'+$_image_height+'"/>');
$_modal.find('.tumblr_iframe').html($_follow_iframe);
$_modal.find('#tumblr-next').attr('data-id',$_post_next);
$_modal.find('#tumblr-prev').attr('data-id',$_post_prev);
}
jQuery('#tumblr_images').on('click','a',function(e){
var $_modal = jQuery('#tumblrModal');
e.preventDefault();
loadTumblrModal(jQuery(this).attr('id'));
$_modal.modal('show');
});
jQuery(document).on('click','.tumblrLink',function(e){
loadTumblrModal(jQuery(this).attr('data-id'));
});
</script>
I must be going crazy. Coffeescript is continualy returning '0' for the difference between two non-equal integers.
x = #location[0]
y = #start[0]
console.log "#{x} - #{y} = #{x-y}"
This is outputting:
350 - 322 = 0
250 - 278 = 0
... and so on
I'm completely confused!
Edit: Here's the source in both coffee and the compiled js
class Branch
constructor: (#length, #start, #angle, #generation, #parent) ->
return if #generation >= RECURSION_LIMIT
#angleVariation = pi/3
#ratio = 2/(1+root(5))
#maxChildren = 10
#parent ?= null
#unit = 2
#children = []
#location = #start
#childLocations = [Math.random()*#length*#ratio/2+(#length*#ratio) \
for n in [0...#maxChildren]]
grow: ->
gl.beginPath()
moveTo #location
#location[0] += #unit * cos(#angle)
#location[1] -= #unit * sin(#angle)
lineTo #location
gl.stroke()
console.log #getLength()
if #getLength() >= #childLocations[#children.length]
#birthChild()
getLength: ->
x = #location[1]
y = #start[1]
console.log "#{x} - #{y} = #{x-y}"
return 1 #root( (#location[0]-#start[0])**2 + (#location[1]-#start[1])**2 )
birthChild: ->
angle = #angle + (Math.random()*#angleVariation*2) - #angleVariation
child = new Branch #length * #ratio, #location, angle, #generation+1, this
And in js:
Branch = (function() {
function Branch(length, start, angle, generation, parent) {
var n, _ref;
this.length = length;
this.start = start;
this.angle = angle;
this.generation = generation;
this.parent = parent;
if (this.generation >= RECURSION_LIMIT) {
return;
}
this.angleVariation = pi / 3;
this.ratio = 2 / (1 + root(5));
this.maxChildren = 10;
if ((_ref = this.parent) == null) {
this.parent = null;
}
this.unit = 2;
this.children = [];
this.location = this.start;
this.childLocations = [
(function() {
var _i, _ref1, _results;
_results = [];
for (n = _i = 0, _ref1 = this.maxChildren; 0 <= _ref1 ? _i < _ref1 : _i > _ref1; n = 0 <= _ref1 ? ++_i : --_i) {
_results.push(Math.random() * this.length * this.ratio / 2 + (this.length * this.ratio));
}
return _results;
}).call(this)
];
}
Branch.prototype.grow = function() {
gl.beginPath();
moveTo(this.location);
this.location[0] += this.unit * cos(this.angle);
this.location[1] -= this.unit * sin(this.angle);
lineTo(this.location);
gl.stroke();
console.log(this.getLength());
if (this.getLength() >= this.childLocations[this.children.length]) {
return this.birthChild();
}
};
Branch.prototype.getLength = function() {
var x, y;
x = this.location[1];
y = this.start[1];
console.log("" + x + " - " + y + " = " + (x - y));
return 1;
};
Branch.prototype.birthChild = function() {
var angle, child;
angle = this.angle + (Math.random() * this.angleVariation * 2) - this.angleVariation;
return child = new Branch(this.length * this.ratio, this.location, angle, this.generation + 1, this);
};
return Branch;
})();
I am have difficulty getting drop and drop to work using Starling with feathers ui.
Here is my code:
function begin(){
var quadx = squareSize/4 + squareSize/8;
var quady = 20;
var quadcounter = 0;
for(var f=0;f<totalsquares;f++){
var sprite:Sprite = new Sprite();
var quad:Quad = new Quad(squareSize, squareSize);
sprite.name = "" + f;
spriteunder.name = "" + f * 1000;
quad.setVertexColor(0, 0x3683ed);
quad.setVertexColor(1, 0x3683ed);
quad.setVertexColor(2, 0x3683ed);
quad.setVertexColor(3, 0x3683ed);
sprite.x=quadx;
sprite.y = quady;
var lv3 = new TextField(squareSize, squareSize, f,"Corpid", 14,0xf1f1f1);
sprite.touchable = true;
quad.touchable = true;
lv3.touchable = false;
sprite.addChild(quad);
sprite.addChild(lv3);
addChild(sprite);
sprite.addEventListener(TouchEvent.TOUCH, touchHandler);
quadx = quadx + squareSize + 1;
quadcounter++;
if(quadcounter == boardWidth){
quadx = squareSize/4 + squareSize/8;
quady = quady + squareSize + 1;
quadcounter = 0;
}
}
}
function touchHandler(e : TouchEvent) : void
{
var touch:Touch = e.getTouch(stage);
var position:Point = touch.getLocation(stage);
var target:Quad = e.target as Quad;
if(touch.phase == TouchPhase.MOVED ){
target.x = position.x - target.width/2;
target.y = position.y - target.height/2;
}
}
The problem is that whenever i run this , its the QUAD child that gets dragged around, not the parent sprite.
What do i change in order to get this to drag correctly.
Perhaps you must start with
var touch:Touch = event.getTouch(this, TouchPhase.BEGAN);
if (touch)
{
//get and lock your target, maybe a trace of your actual target, just to be sure!
}
And then in the MOVED phase, actually drag it.