Javascript-форум (https://javascript.ru/forum/)
-   Оффтопик (https://javascript.ru/forum/offtopic/)
-   -   Получить все точки отрезка прямой? (https://javascript.ru/forum/offtopic/52479-poluchit-vse-tochki-otrezka-pryamojj.html)

Gozar 21.12.2014 16:01

Получить все точки отрезка прямой?
 
Как получить все точки отрезка прямой (на canvas)?
Известно x1, y1, x2, y2

Допенькал как получить точки прямой по Алгоритму Брезенхема до 45* градусов. Если переставить x и y можно даже получить все точки до 90*.

Но не могу понять как получить все точки, если x2 < x1 или y2 < y1

Может как-то через отражение?

kobezzza 21.12.2014 16:13

Если я правильно понял задачу, то
http://www.cleverstudents.ru/line_an..._segments.html

рони 21.12.2014 16:15

Gozar,
:write: нарисовать чёрным по белому на невидимом холсте потом прогнать весь холст записав в массив все точки цвета Black не белые

Gozar 21.12.2014 16:22

Цитата:

Сообщение от рони
нарисовать

похоже на здравствуй тормоза! Идея интересная, но мне нужно то, что kobezzza предлагает. У меня нагруженный алгоритм и мне таких плоскостей придется создавать просто дофига, а это точно тормоза


kobezzza,
Хотелось бы в программном коде, а не геометрии. В алгоритмах куча оптимизаций, а я буду изобретать велосипед.

А по Брезенхему не встречался?

По сути мне нужно достроить между точками прямую, точек у меня таких много и они динамически создаются очень быстро.

kobezzza 21.12.2014 16:32

Ну я хз про оптимизации, но есть общая формула:

x / a + y / b = 1


где a и b удаление от начала координат по X и Y, т.е. подставляешь a и b, затем делаешь шаг по X или Y (шаг определяешь сам, например 1px) и вычисляешь второе значение.

Думаю, что есть специальные алгоритмы, но я тут не в теме особо.

Gozar 21.12.2014 16:35

kobezzza,
Спасибо за участие, я формулы видел, а потом посмотрел лекцию по графике и понял, что лучше взять готовый алгоритм, с оптимизацией. Нашел тут на каком-то неизвестном языке програ-я написан, ща попробую переписать :D

рони 21.12.2014 17:27

:write: мысли вслух любой блок анимации на js выдаст необходимый массив точек --даже точность можно регулировать.

Gozar 21.12.2014 17:35

Цитата:

Сообщение от рони
любой блок анимации

У меня нет анимации, зато есть события, которые браузер отлавливает с разрывами, мне нужно соединить точки, где браузер не отлавливает событие перемещения курсора.

рони 21.12.2014 17:48

Gozar,
<script>
var x = 5, y = 5, x2 = 2, y2 = -10;
var time = Math.abs(x - x2);
for (var i=0; i<=time; i++)  {
  var delta = i/time ;
  var a =  delta*(x2 - x) + x;
  var b =  delta*(y2 - y) + y;
  document.write([a,b]+"<br>")
}
</script>

рони 21.12.2014 18:07

:write:
<script>
var x = 50, y = 50, x2 = 20, y2 = -10;
var time = Math.max( Math.abs(x - x2), Math.abs(y - y2));//для повышения точности выбираем что сильнее изменилось, для ускорения выбор наоборот min
for (var i=0; i<=time; i++)  {
  var delta = i/time ;
  var a =  delta*(x2 - x) + x;
  var b =  delta*(y2 - y) + y;
  document.write([Math.round(a),Math.round(b)]+"<br>")
}
</script>

Gozar 21.12.2014 18:11

рони,
Вот тебе функция:

//<canvas id="canvas" width="300" height="300" style="border: 1px solid #000"></canvas>

    function setPixel (x, y) {

        ctx.beginPath();
        ctx.moveTo(x,y);
        ctx.arc(x, y, 1, 0, Math.PI*2, true);
        ctx.fill();
        ctx.closePath();
    }
var canvas = document.getElementById('canvas'),
ctx = canvas.getContext('2d');
ctx.fillStyle = 'rgba(0,0,0,1)';


Можешь нарисовать на канвас то, что у тебя получилось?

Я не очень понимаю куда мне подставлять отрицательные значения из твоего кода.

Вот координаты двух линий:
x1 = 10, y1 = 10, x2 = 100, y2 = 100;
x1 = 10, y1 = 100, x2 = 100 y2 = 10;

JsLoveR 21.12.2014 18:42

Цитата:

Сообщение от Gozar
Допенькал как получить точки прямой по Алгоритму Брезенхема до 45* градусов. Если переставить x и y можно даже получить все точки до 90*.

Данный алгоритм подходит для абсолютно любых линий. Вот можно поиграться в песочнице.

function drawLineTo(x1, y1, x2, y2) {
	var deltaX = Math.abs(x2 - x1),
		deltaY = Math.abs(y2 - y1),
		signX = x1 < x2 ? 1 : -1,
		signY = y1 < y2 ? 1 : -1,
		error = deltaX - deltaY;
		
		setPixel(x2, y2);
		
	while (x1 != x2 || y1 != y2) {
			
		setPixel(x1, y1);
			
		var error2 = error * 2;
			
		if (error2 > -deltaY) {
			error -= deltaY;
			x1 += signX;
		}
			
		if (error2 < deltaX) {
			error += deltaX;
			y1 += signY;
		}
	}
}

рони 21.12.2014 18:56

Цитата:

Сообщение от Gozar
Можешь нарисовать на канвас то, что у тебя получилось?

<!DOCTYPE HTML>

<html>

<head>
  <title>Untitled</title>
</head>

<body>
<canvas id="canvas" width="300" height="300" style="border: 1px solid #000"></canvas>

<script>

    function setPixel (x, y) {

        ctx.beginPath();
        ctx.moveTo(x,y);
        ctx.arc(x, y, 1, 0, Math.PI*2, true);
        ctx.fill();
        ctx.closePath();
    }
var canvas = document.getElementById('canvas'),
ctx = canvas.getContext('2d');
ctx.fillStyle = 'rgba(0,0,0,1)';

x1 = 10, y1 = 10, x2 = 100, y2 = 100;
var time = Math.abs(x1 - x2);
for (var i=0; i<time; i++)  {
  var delta = i/time ;
  var a =  delta*(x2 - x1) + x1;
  var b =  delta*(y2 - y1) + y1;
  setPixel(a,b)
}
x1 = 10, y1 = 100, x2 = 100, y2 = 10;
var time = Math.abs(x1 - x2);
for (var i=0; i<time; i++)  {
  var delta = i/time ;
  var a =  delta*(x2 - x1) + x1;
  var b =  delta*(y2 - y1) + y1;
  setPixel(a,b)
}


</script>
</body>

</html>

Gozar 21.12.2014 19:02

JsLoveR,
Спасибо. Я нашел немного другой, он по скорости чуть чуть быстрее:

function setLine (x1, y1, x2, y2) {
    var x = x1,
        y = y1;
    var dx = Math.abs(x2-x1),
        dy = Math.abs(y2-y1);
    var sx = (x2-x1)>0?1:((x2-x1)==0?0:-1);
    var sy = (y2-y1)>0?1:((y2-y1)==0?0:-1);
    var tx, ty;
    var z, scount, count, dcount;

    if (dx>=dy) {
        tx = sx; ty = 0;
    } else {
        z=dx; dx=dy; dy=z;
        tx=0; ty=sy;
    }

    scount = 2*dy;
    count = scount-dx;
    dcount = count-dx;

    for(;;) {

        dx -= 1;

        if (dx < -1){
            break;
        }

        setPixel(x, y);

        if (count >= 0) {
            x+=sx;
            y+=sy;
            count += dcount;

        } else {
            x+=tx;
            y+=ty;
            count += scount;
        }
    }
}

__он_самый__ 21.12.2014 19:04

Цитата:

Сообщение от Gozar
похоже на здравствуй тормоза!

этот трюк исполоьзуют например чтобы проверить находится ли курсор внутри сложной фигуры или во вне её, рисуют фигуру на невидимой канве WEBGL зеленым цветом, и проверяют какого цвета пиксель в нужной координате, белый или зеленый. и это быстре чем самому яваскриптом вычислять. Можно хоть 30 фигур нарисовать разными цветами и определить на какую наведен курсор)

эт на будущее, по скольку спускаемся на уровень абстракции ниже ближе к железу, то это раз в сто быстрее чем яваскриптом считать

Этим же трюком можно чекать пересекаются ли фигуры в физических яваскрипт движках)

аппаратное ускорение хули

__он_самый__ 21.12.2014 19:07

for(;;)


не пиши так больше, пиши while(true) как все нормальные люди, и даже не while(1), именно while(true), как взрослый образованный человек, не дикарь.

Gozar 21.12.2014 19:08

рони,
Что-то не работает:
<!DOCTYPE HTML>

<html>

<head>
  <title>Untitled</title>
</head>

<body>
<canvas id="canvas" width="1000" height="1000" style="border: 1px solid #000"></canvas>

<script>

    function setPixel (x, y) {

        ctx.beginPath();
        ctx.moveTo(x,y);
        ctx.arc(x, y, 1, 0, Math.PI*2, true);
        ctx.fill();
        ctx.closePath();
    }
var canvas = document.getElementById('canvas'),
ctx = canvas.getContext('2d');
ctx.fillStyle = 'rgba(0,0,0,1)';

function ronyLine (x1, y1, x2, y2) {

    var time = Math.abs(x1 - x2),
        a, b, delta, i;

    for (i=0; i<time; i++)  {
      delta = i/time;
      a =  delta*(x2 - x1) + x1;
      b =  delta*(y2 - y1) + y1;
      setPixel(a,b)
    }
}
    for(var i=0;i<1000;i+=1) {
        ronyLine(10, 10, i, 200);
    }

</script>
</body>

</html>


Упс, работает, но что-то мне подсказывает, что лучше так не делать :)

Gozar 21.12.2014 19:09

__он_самый__,
Цитата:

Сообщение от __он_самый__
этот трюк исполоьзуют например чтобы проверить находится ли курсор внутри сложной фигуры или во вне её

https://developer.mozilla.org/en-US/....isPointInPath

рони 21.12.2014 19:11

Gozar,
28 строка зачем?

Gozar 21.12.2014 19:14

Цитата:

Сообщение от __он_самый__ (Сообщение 347503)
for(;;)


не пиши так больше, пиши while(true) как все нормальные люди, и даже не while(1), именно while(true), как взрослый образованный человек, не дикарь.

Можно и так. Просто код был с java списан, было не до украшательств. На скорости это не отразилось. Пусть будет while(true)

Gozar 21.12.2014 19:16

Цитата:

Сообщение от рони
Gozar,
28 строка зачем?

Не догоняю, можешь функцию правильно написать? Я вроде без изменений обернул в функцию. Если косяк, объясни, голова уже плохо варит к вечеру.

рони 21.12.2014 19:20

Gozar,
ты уже сам убрал косяк -- аргументы перезаписывались в строке 28

Gozar 21.12.2014 19:23

рони,
Ты видел результат? Почему он такой? Вначале не линия, а сетка.

рони 21.12.2014 19:32

Gozar,
точность расчётов

<!DOCTYPE HTML>

<html>

<head>
  <title>Untitled</title>
</head>

<body>
<canvas id="canvas" width="1000" height="1000" style="border: 1px solid #000"></canvas>

<script>

    function setPixel (x, y) {

        ctx.beginPath();
        ctx.moveTo(x,y);
        ctx.arc(x, y, 1, 0, Math.PI*2, true);
        ctx.fill();
        ctx.closePath();
    }
var canvas = document.getElementById('canvas'),
ctx = canvas.getContext('2d');
ctx.fillStyle = 'rgba(0,0,0,1)';

function ronyLine (x1, y1, x2, y2) {

    var time = Math.max( Math.abs(x1 - x2), Math.abs(y1 - y2)),  //оптимальная точность
        a, b, delta, i;
        time = 1000// точность для маньяков
    for (i=0; i<time; i++)  {
      delta = i/time;
      a =  delta*(x2 - x1) + x1;
      b =  delta*(y2 - y1) + y1;
      setPixel(a,b)
      //setPixel(Math.round(a),Math.round(b)) //по желанию
    }
}
    for(var i=0;i<1000;i+=10) {
        ronyLine(10, 10, i, 200);
    }

</script>
</body>

</html>

Gozar 21.12.2014 19:39

рони,
Это все прикольно, но в тесте пикселы закрашены не все, а значит ф-ия не подходит, с учетом того, что она еще и немного медленнее других.

рони 21.12.2014 19:52

Gozar,
померяй этот вариант )))
<!DOCTYPE HTML>

<html>

<head>
  <title>Untitled</title>
</head>

<body>
<canvas id="canvas" width="1000" height="520" style="border: 1px solid #000"></canvas>
<script>
function setPixel(x, y) {

    ctx.beginPath();
    ctx.moveTo(x, y);
    ctx.arc(x, y, 1, 0, Math.PI * 2, true);
    ctx.fill();
    ctx.closePath();
}
var canvas = document.getElementById('canvas'),
    ctx = canvas.getContext('2d');
ctx.fillStyle = 'rgba(0,0,0,1)';

function ronyLine(x1, y1, x2, y2) {
    var x = Math.abs(x1 - x2),y = Math.abs(y1 - y2) ;
    var time = Math.sqrt(x*x + y*y)|0, //    больше точек, чем это число на линии нет
        a, b, delta, i;
    var xx = (x2 - x1) + x1, yy = (y2 - y1) + y1 ; //типа кеш

    for (i = 0; i < time; i++) {
        delta = i / time;
        a = delta * xx;
        b = delta * yy;
        setPixel(a, b)

    }
}
for (var i = 0; i < 1000; i += 10) {
    ronyLine(10, 10, i, 500);
}
</script>
</body>

</html>

JsLoveR 21.12.2014 20:03

Иногда можно заюзать линейную "кривую" безье.
function bezierLineTo(x1, y1, x2, y2) {
	var step = 0.0001; //для большей точности можно находить дистанцию между точками, тогда step = 1 / distance
		
	for (var t = 0; t < 1; t += step) {
		var x = (1 - t) * x1 + t * x2;
		var y = (1 - t) * y1 + t * y2;
			
		setPixel(x, y);
	}
}

Gozar 21.12.2014 20:26

Цитата:

Сообщение от JsLoveR (Сообщение 347515)
Иногда можно заюзать линейную "кривую" безье.

В копилку, будет следующий этап.

Кстати кто-нибудь знает какой-нибудь очень быстрый рандом? вот этот:
Math.floor(Math.random() * (max - min + 1)) + min;

очень медленный.

Подойдет от 1 до 360.

рони 21.12.2014 20:32

Gozar,
а если один раз сформировать массив рандомный и пользоваться

nerv_ 21.12.2014 20:52

Цитата:

Сообщение от Gozar
Получить все точки отрезка прямой?
Известно x1, y1, x2, y2

Отвечу, как понял. Все точки прямой - длинна прямой.

1. По точкам строишь вектор. Координаты вектора: x = x2-x1, y = y2-y1
2. Находишь длину (модуль) вектора: sqrt(x^2 + y^2)

Если требуется, переводишь декартовы координаты в полярные (или наоборот).

рони 21.12.2014 21:01

Цитата:

Сообщение от nerv_
Находишь длину (модуль) вектора: sqrt(x^2 + y^2)

Цитата:

Сообщение от рони
var time = Math.sqrt(x*x + y*y)|0, // больше точек, чем это число на линии нет

:victory:
генератор цепочек случайных данных
<!DOCTYPE HTML>
<html>
<head>
  <title>Untitled</title>
</head>
<body>
<script>   var time = new Date();
function rund(e, f) {
        function d(b) {
            for (var a = b.length - 1; 0 < a; a--) {
                var c = Math.floor(Math.random() * (a + 1)),
                    d = b[c];
                    b[c] = b[a];
                    b[a] = d
            }
            return b
        }
        var a = [],
            c = [];
        for (i = 0; i < e; i++) a[i] = i + f;
        d(a);
        return function () {
            var b = a.shift();
            c.push(b);
            1 == a.length && (d(c), a = a.concat(c), c = []);
            return b
        }
    };

 var len = 360,
     min = 1,
     z = rund(len,min),
     i;

 var arr = [];
 for (i = 0; i < 15000; i++) { //можно любой длины равномерность случайности сохранится или просто вместо random использовать z()
   arr[i]= z()

 }
 alert((new Date).getTime() - time.getTime()); //10ms на генерацию 15000 вариантов

for (var i=0; i<arr.length; i++)  {document.write(arr[i]+" ")}
  //для примера

</script>
</body>
</html>

Gozar 21.12.2014 21:06

nerv_,
Как найти все x между x1 и x2?
и с y тоже самое.

nerv_ 21.12.2014 21:21

Цитата:

Сообщение от Gozar
Как найти все x между x1 и x2?

от 0 до 1 бесконечное количество точек :)

Можно задать неравенством / множеством. Но тебе данные случаи, как я понял, не нужны.

Скорее всего ты поставил задачу неправильно, вследствии чего можешь найти решение. Попробуй сформулировать задачу в более общем виде.

рони 21.12.2014 21:42

:write: на всякий случай случайный ... но медленнее(чуть) и конечно менее случайный (зато свой random, не использует встроенный метод Math.random)

http://chancejs.com/
<!DOCTYPE HTML>

<html>

<head>
  <title>Untitled</title>
</head>

<body>
 <script type="text/javascript" src="http://chancejs.com/chance.js"></script>
<script> var time = new Date();
  var arr = [];
  for (var i=0; i<15000; i++)  {arr[i]=chance.integer({min: 1, max: 360})}
   alert((new Date).getTime() - time.getTime()); //10ms на генерацию 15000 вариантов

for (var i=0; i<arr.length; i++)  {document.write(arr[i]+" ")}
</script>
</body>

</html>

Gozar 21.12.2014 22:18

Цитата:

Сообщение от nerv_
Скорее всего ты поставил задачу неправильно, вследствии чего можешь найти решение. Попробуй сформулировать задачу в более общем виде.
_____

2 страницы назад задачу решили и даже в 2х практически равнозначных по скорости вариантах. Один алгоритм я переписал с java, а второй подсказал JsLoveR, за что ему отдельное спасибо!

Если хочешь могу написать, что нужно найти не все точки прямой, а координаты всех точек отрезка прямой на плоскости. Хотя я думал что если canvas то должно быть понятно, что на плоскости. Хотя я уже подумываю о нахождении точек кривой безье :)

melky 21.12.2014 22:24

Цитата:

Сообщение от Gozar
Если хочешь могу написать, что нужно найти не все точки прямой, а координаты всех точек отрезка прямой на плоскости.

зависит от точности... вообще - их бесконечно много. квантовать как будем?)

Цитата:

Сообщение от nerv_
от 0 до 1 бесконечное количество точек

запахло матаном

Gozar 21.12.2014 22:29

Цитата:

Сообщение от melky
квантовать как будем?)

попиксельно. canvas значит растр, значит попиксельно. чего здесь бесконечно много искать?

nerv_ 21.12.2014 23:53

Цитата:

Сообщение от Gozar
попиксельно. canvas значит растр, значит попиксельно. чего здесь бесконечно много искать?

ну, как бы scale() ...

Цитата:

Сообщение от Gozar
хотя я думал что если canvas то должно быть понятно, что на плоскости

Понятно было из координат. У канвы есть 3d если что :)

Gozar 21.12.2014 23:59

Цитата:

Сообщение от nerv_
У канвы есть 3d если что

Цитата:

Сообщение от Gozar
Как получить все точки отрезка прямой (на canvas)?
Известно x1, y1, x2, y2

В условии задачи нет z1, z2, если что ;)

l-liava-l 26.12.2014 04:15

Любая метрическая система делит что-то на секции с определнной погрешностью.
В нашем случае секции - это пиксели. Например прямая длиной 137px имеет 137 точек.

Gozar

x2 - x1 = x длина первого катета
y2 - y1 = y длина второго катета

Квадрат гипотинузы равен сумме квадратов катетов...
Если хочется получить кординаты какой то точки на гипотинузе то составляй тройную пропорцию.


Надеюсь я правильно понял вопрос


Часовой пояс GMT +3, время: 00:30.