Comments 65
Очень подробно и понятно. Что касается изометрики, не совсем мне кажется доступно описано.
Но так и потянуло открывать редактор и пробывать различные трансформации.
Но так и потянуло открывать редактор и пробывать различные трансформации.
Спасибо, очень познавательно. А про кривые безье будет статья?
Кривые Безье — это намного проще, на статью не тянет. Глянем на MDC интерфейс:
Тут главное разобраться за какую точку отвечает каждый из аргументов. Вы можете использовать LibCanvas PathBuilder для экспериментов.

Оранжевая точка — это точка, из которой мы начинаем рисовать кривую, её положение показывает где закончился путь перед этим, например от аргумента moveTo или последняя точка предыдущего вызова bezierCurveTo.
Аргументы x, y отвечают за изменения положения жёлтой точки, которая указывает куда следует проложить кривую, аргументы cp1x, cp1y за изменения положения контрольной розовой точки, а cp2x, cp2y – контрольной голубой.
bezierCurveTo(cp1x, cp1y, cp2x, cp2y, x, y)
Тут главное разобраться за какую точку отвечает каждый из аргументов. Вы можете использовать LibCanvas PathBuilder для экспериментов.

Оранжевая точка — это точка, из которой мы начинаем рисовать кривую, её положение показывает где закончился путь перед этим, например от аргумента moveTo или последняя точка предыдущего вызова bezierCurveTo.
Аргументы x, y отвечают за изменения положения жёлтой точки, которая указывает куда следует проложить кривую, аргументы cp1x, cp1y за изменения положения контрольной розовой точки, а cp2x, cp2y – контрольной голубой.
Извините за не энциклопедическое объяснение)
Спасибо, понятно. Просто я уж коль вы разбираете в геометрических преобразованиях, хотел бы поинтересоваться как построить параллельную кривую, кривой бизье. Заданную 3мя точками. Надеюсь понятно что я имею в виду (например железнодорожные шпалы).
Для того, чтобы построить параллельную кривую необходимо сдвинуть на определённое значение х или у. Главное — сохранить растояние между всеми точками фигуры. К примеру, если Вам нужно построить параллельную кривую справа от первичной, то необходимо все иксы увеличить на N.
Можно, но таким образом мы получим не равноценные окончания отрезков. Ладно, без примера сложно объяснить. Там нужно вычислять новые точки. У меня есть идея, думал может еще, что подскажите. Спасибо. Будет интересно нарисую.
Мне интересно. Особенно про пункт «неполноценные окончания». Что вы имеете ввиду? Если так критично сделать клона кривой — почему бы ее на нарисовать в буфер, а потом из него — две кривых
Буфер не нужен. Мне скорее требуется не клона, а кривую, которая будет полностью параллельна. Завтра я напишу комментарий тут, где приведу пример, и решение свое. Сегодня просто не успею.
Насколько я понял из описания, Вам нужна эквидистанта.
И так, у нас есть кривая, построенная по трем точкам.
Если мы просто сдвинем, то у нас получиться, что то такое.
На параллельные путь, ЖД не очень похоже.
Во что мне бы хотелось видеть.
Красная и синяя кривые.
Теперь опишу алгоритм как я это получаю.
Проводим отрезки АК и ВК в 3 точку кривой бизье.
Перпендик. им я строю прямые a и b. На этих прямых откладываю 2 равных отрезка AC и BD.
Это и будут новые точки кривой бизье. Но как найти 3ю точку.
Я провожу 2 параллельные прямые DF || BK и CF || AK.
И на их пересечении я нахожу точку F. Какая и является искомой. Вот так, я строю.
Сам алгорим я ещё не проверил(до этого я искал по другому, но оказалось ошибачно), может это и не правильно, или может есть ещё какой то более простой способ, поэтому и спрашиваю.
И ещё. Так как я не знаю как построить параллельные(может есть алгорим). То провожу перпендикулярные прямые, не только к точкам B и A. Но и в точку К я опускаю 2 перпендикуляра как к одной прямой так и к другой.
Если мы просто сдвинем, то у нас получиться, что то такое.
На параллельные путь, ЖД не очень похоже.
Во что мне бы хотелось видеть.
Красная и синяя кривые.
Теперь опишу алгоритм как я это получаю.
Проводим отрезки АК и ВК в 3 точку кривой бизье.
Перпендик. им я строю прямые a и b. На этих прямых откладываю 2 равных отрезка AC и BD.
Это и будут новые точки кривой бизье. Но как найти 3ю точку.
Я провожу 2 параллельные прямые DF || BK и CF || AK.
И на их пересечении я нахожу точку F. Какая и является искомой. Вот так, я строю.
Сам алгорим я ещё не проверил(до этого я искал по другому, но оказалось ошибачно), может это и не правильно, или может есть ещё какой то более простой способ, поэтому и спрашиваю.
И ещё. Так как я не знаю как построить параллельные(может есть алгорим). То провожу перпендикулярные прямые, не только к точкам B и A. Но и в точку К я опускаю 2 перпендикуляра как к одной прямой так и к другой.
Во-первых, у Вас на картинках изображена квадратичная кривая Безье, это на всякий случай.
Во-вторых, что изображено на рисунках, то и называется эквидистантой. К сожалению, я не программист, и даже не математик. Поэтому не могу помочь алгоритмом или формулой.
Но теперь, зная название, Вам будет гораздо проще найти информацию по предметной области. У меня, например, нашлась вот такая забавная статья.
Во-вторых, что изображено на рисунках, то и называется эквидистантой. К сожалению, я не программист, и даже не математик. Поэтому не могу помочь алгоритмом или формулой.
Но теперь, зная название, Вам будет гораздо проще найти информацию по предметной области. У меня, например, нашлась вот такая забавная статья.
Тут мне подсказывают, что кривая Безье второго порядка является сегментом параболы. Также нужно заметить, что эквидистанта к параболе не является параболой.
картинки не открываются
Приятно когда девушки пишут такие статьи. Спасибо, только начал вникать в Canvas, будет полезно.
К тому же девушки, которым 19 лет o_O
Вы знаете много 19-ти летних девушек, пишуших на хабр про элементарную геометрию в джаваскрипте? :-)
это не элементарная геометрия – это Аффинное преобразование
неправильно дано определение параметрам m11,m12,m21,m22.
m11 = scaleX * cos(alpha),
m12 = scaleY * sin(alpha),
m21 = -scaleX * sin(alpha),
m12 = scaleY * cos(alpha),
где scaleX,scaleY — сжатие растяжение вдоль соответствующей оси, а alpha — угол поворота.
m11 = scaleX * cos(alpha),
m12 = scaleY * sin(alpha),
m21 = -scaleX * sin(alpha),
m12 = scaleY * cos(alpha),
где scaleX,scaleY — сжатие растяжение вдоль соответствующей оси, а alpha — угол поворота.
И на сколько это поможет не понимающим людям понять, что делает каждый из аргументов? Цель этой статьи ведь не в том, чтобы процитировать технические определения, а обьяснить доступным языком, что можно было без заминки использовать трансформации
эта матрица является обобщением методов scale, translate и rotate(произведением матриц) и мне кажется если люди поняли как работают эти методы по отдельности, то их не нужно вводить в заблуждение, а дать точное описание параметров
Точное описание параметров можно найти в любой «умной» статье про трансформации. Они дают мало понимания менее опытным программистам. Важно понять, как оно работает, а не заучить технические определения
Хочу обратить внимание — я не спорю, что желательно глубокое понимание принципов трансформации, более того, сам достаточно хорошо разбираюсь в этом, но такие детали в ЭТОЙ статье только запутают разбирающегося. Любой желающий, прочтя нашу ветку комментариев в легкостью найдет более точные, но менее очевидные описания.
Я так же не спорю. Просто я не понимаю, то описание которое дал автор, мне кажется оно не корректным. Хотя для новичков — это старт, чтобы понять предмет трансформации.
спросите у новичков, насколько точное определение помогает им понять предмет трансформации
Вы зануда.
Автор молодец, доступно все объяснила, я не думаю что эта статья предназначается для опытных программистов, разбирающихся в терминологии.
Автор молодец, доступно все объяснила, я не думаю что эта статья предназначается для опытных программистов, разбирающихся в терминологии.
немножко иксы-игреки перепутаны.
то что я написал это полный вариант, матрица трансформации — это перемножение трех матриц: поворота, растяжения и параллельного переноса.
я подправил только коэффициенты m11-m22. Я вам говорю про матрицу трансформации на плоскости. Она имеет размер 3х3, и да на плоскости существую только поворот, сжатие и параллельный перенос.
и я повторюсь для меня проще сухие формулы, я ни кого не заставляю ими пользоваться.
только поворота и растяжения. для переноса нужно вводить третюю координату.
перенос это самая простая трансформация. Она имеется даже в R1.
shatalov.su/math/transformation_1.php глава про однородные координаты в самом конце
"… он шире в два раза чем выше"
После прочтения вспомнилось:
Любая девушка может доказать, что крокодил более зеленый чем широкий...)))
После прочтения вспомнилось:
Любая девушка может доказать, что крокодил более зеленый чем широкий...)))
Эх, жаль в канвасе нет матричных преобразований цвета пикселей… Руками это делать как-то чертовски долго выходит.
В тестировании матрицы ввел ошибочные параметры — канва упала, и перестала реагировать даже на корректные данные. Помог F5.
в изометрии между тайлами белые точки. как это побороть?
Где же Ваши собственные фотографии на этот раз?
Я сейчас для развлечения и изучения canvas пишу игру Scorch, мне там понадобилась совмещать трансформации, крутить вокруг выбранной точки, для этого просто написал Matrix2d
Очень удобно пользоваться:
Очень удобно пользоваться:
new Matrix2d(). Rotate(angle, rotationPoint). FlipY(rotationPoint). CreateTransform(context);
function Matrix2d () { var _matrix = [[1, 0, 0], [0, 1, 0], [0, 0, 1]]; var CalcOffset = function (matrix) { var x = matrix[0][2] * matrix[0][0] + matrix[1][2] * matrix[0][1]; var y = matrix[0][2] * matrix[1][0] + matrix[1][2] * matrix[1][1]; matrix[0][2] -= x; matrix[1][2] -= y; return matrix; } var Multiply = function (matrix) { var mulMatrix = [[0, 0, 0], [0, 0, 0], [0, 0, 0]]; for (var x = 0; x < 3; x++) { for (var y = 0; y < 3; y++) { var sum = 0; for (var dim = 0; dim < 3; dim++) { sum += _matrix[y][dim] * matrix[dim][x]; } mulMatrix[y][x] = sum; } } _matrix = mulMatrix; } this.Rotate = function (angle, point) { var sin = Math.sin(angle); var cos = Math.cos(angle); Multiply(CalcOffset([ [cos, -sin, point.x], [sin, cos, point.y], [0, 0, 1] ])); return this; } this.FlipY = function (point) { Multiply(CalcOffset([ [-1, 0, point.x], [0, 1, point.y], [0, 0, 1] ])); return this; } this.FlipX = function (point) { Multiply(CalcOffset([ [1, 0, point.x], [0, -1, point.y], [0, 0, 1] ])); return this; } this.FlipXY = function (point) { Multiply(CalcOffset([ [-1, 0, point.x], [0, -1, point.y], [0, 0, 1] ])); return this; } this.CreateTransform = function (context) { context.transform( _matrix[0][0], _matrix[1][0], _matrix[0][1], _matrix[1][1], _matrix[0][2], _matrix[1][2]); return this; } }
sylvester.jcoglan.com/ видели?)
Видел, но только для перемножений матриц брать её не имеет смысла. У них для 2d используется матрица 2x2 — у меня 3x3, что позволяет заодно и смещения считать, крутить вокруг нужной точки, отражать вокруг нужной точки. Плюс возможность цепочки трансформаций. Добавление новой функциональности сводится к добавлению 9 строк кода и новой матрицы в них.
В моём случае поддержка и расширение легче и, самое главное, кода намного меньше.
Да и условия лицензии не надо исполнять ;-)
В моём случае поддержка и расширение легче и, самое главное, кода намного меньше.
Да и условия лицензии не надо исполнять ;-)
«сплюскиваем» =)
Sign up to leave a comment.
Canvas-трансформации доступным языком