forum.boolean.name

forum.boolean.name (http://forum.boolean.name/index.php)
-   2D-программирование (http://forum.boolean.name/forumdisplay.php?f=13)
-   -   Пунктирная окружность (http://forum.boolean.name/showthread.php?t=20020)

DarkInside 04.10.2015 02:58

Пунктирная окружность
 
Приветствую, форумчане!

Появилась необходимость рисовать пунктирную окружность. При этом она должна состоять не из точек, а из линий длиной 4 пикселя и промежуток между ними 2 пикселя.
Поиск ничего не дал. Четыре часа ломал голову, вспоминал формулы окружности. Либо я туплю, либо что-то не учитываю, но если просто рисовать точками (а потом разделить их на отрезки) по функции y = +-Sqr (r^2-x^2), то при y, приближающемся к нулю, точки почему-то не все прорисовываются. В итоге пришлось разбить окружность на 4 части и рисовать по-отдельности. Второй момент: длина окружности ведь 2*Пи*r, если разделить на 4 части и еще на 2 (отрицательные и положительные значения), то цикл должен выглядеть так: For x = -Пи*r/4 To Пи*r/4. То есть получаем Пи/4 = 0,7854*r. Но при таком значении части окружности почему-то накладываются друг на друга. Подобрал экспериментально число 0.7067. Откуда оно взялось непонятно. В математике такого нет.
В общем, вот то, на что меня хватило:
Проблемы следующие:
1) вроде делаю шаг 4 пикселя (целочисленное деление), а получаются линии по 8 пикселей. Промежуток 5 пикселей (хотя при 8 должен быть 4, если в 2 раза меньше).
2) при радиусе 100 вроде окружность выглядит нормально, а вот при радиусе 200 и более стыки между четырьмя её частями сливаются.
Может кто подскажет решение попроще и поэлегантнее?
Ну или может кто заметит косяк, а то я совсем запутался, уже на бумаге всё разрисовал, а в коде не получается :rolleyes:

PHP код:

Graphics 800,600,32

Dim kr_x 
(1)
Dim kr_y (1)

While 
Not KeyHit(1
    
    
Color 255255255
    
    
If KeyHit (57Then dotted_circle (400300100)
    
Wend  

Function dotted_circle (dxdyr)
    
For 
= -0.7067*r To 0.7067*r
    y 
Sqr (r^x^2)
    If 
x Mod 4 0 Then 
        rf 
rf 1
    
EndIf
Next

Dim kr_x 
(rf)
Dim kr_y (rf)

For 
= -0.7067*r To 0.7067*r
    y 
Sqr (r^x^2)
    If 
x Mod 4 0 Then 
        kr_x 
(i) = x
        kr_y 
(i) = y
        i 
1
    
EndIf
Next

For 0 To rf Step 4
    Line kr_x 
(i) + dxkr_y (i) + dykr_x (i+2) + dxkr_y (i+2) + dy
    Line kr_x 
(i) + dx, -kr_y (i) + dykr_x (i+2) + dx, -kr_y (i+2) + dy
    Line kr_y 
(i) + dxkr_x (i) + dykr_y (i+2) + dxkr_x (i+2) + dy
    Line 
-kr_y (i) + dxkr_x (i) + dy, -kr_y (i+2) + dxkr_x (i+2) + dy
Next

rf 
00

End 
Function 


impersonalis 04.10.2015 03:10

Ответ: Пунктирная окружность
 
y=r*sin(q)
x=r*cos(q)
При известном r оцениваешь значение шага для q. Генерируешь набор точек. Соединяешь линиями. всё
Блитца под рукой нет

DarkInside 04.10.2015 03:27

Ответ: Пунктирная окружность
 
Спасибо! Проверил, работает.
Всё проще, оказывается. Обидно, что 4 часа провозился с разбиением окружности на части.
Хреново, когда не помнишь геометрию. Я даже не подумал про синусы косинусы, потому что их графики мне представляются в виде волны, а не окружности.

PHP код:

Graphics 800,600,32

While Not KeyHit(1
    
    
Color 255255255
    
    
For 1 To 1000 Step 4
        Plot 400
+200*Cos(q), 300+200*Sin(q)
    
Next
    
Wend 


polopok 04.10.2015 07:02

Ответ: Пунктирная окружность
 
Кстати , если кому надо , то ...
Функция Пунктирная линия с регулируемым шагом
- - - - - - - - - - - - - - - - - - - - - - - - -
шаг задаёт переменная offsete
Код под спойлером :
Код:


Function Interpolate#(stepInterpolate#, Pt_1#, Pt_2#)
    Return ((1.0-stepInterpolate)*Pt_1 + stepInterpolate *Pt_2)
End Function

Function StepLine#(sPt_x# ,sPt_y#, ePt_x# ,ePt_y# , R_ = 255,G_ = 255,B_ = 255 , offsete = 4)
offsete = Int(offsete )
If offsete <1 Then offsete =1
step_line# = 1.0 /((sPt_x- ePt_x)*(sPt_x- ePt_x) + (sPt_y- ePt_y)*(sPt_y- ePt_y))^0.5 *offsete
local_step_line# = 0.0
local_step_line_2# = local_step_line# - step_line
While local_step_line<1.0
    local_x# = Interpolate#(local_step_line, sPt_x, ePt_x)
    local_y# = Interpolate#(local_step_line, sPt_y, ePt_y)
   
    local_step_line_2 = local_step_line + step_line   
    If local_step_line_2 < 0.0 local_step_line_2 = local_step_line
   
    local_x2# = Interpolate#(local_step_line_2, sPt_x, ePt_x)
    local_y2# = Interpolate#(local_step_line_2, sPt_y, ePt_y)   
    switch = Not switch
    If switch   
                Color R_ ,G_ ,B_
                Line local_x , local_y ,local_x2 , local_y2
    EndIf
    local_step_line = local_step_line + step_line
   
Wend   
End Function


impersonalis 04.10.2015 23:42

Ответ: Пунктирная окружность
 
Цитата:

Сообщение от DarkInside (Сообщение 300166)
Спасибо! Проверил, работает.

Пожалуйста. Зашёл в тред - думал будет не довольный коммент про лапидарность моего ответа. Уже думал набросать код именно с линиями (т.е. аппроксимацию окружности отрезками, а не кривыми [образованными точками] как сейчас) - а тут оказывается уже всё решилось. Обращайся. ;)

По коду:


For q = 1 To 360 Step 4

upd: правомочное уравнение r^2=x^2+y^2 (упомянутое тобой) удобно использовать для определения принадлежности заданной точки указанной кривой (окружности). Само по себе оно корректно, просто, для данной задачи неудобно. Надо будет перебрать значения от 0 до r => получить два y => отражением получить из каждого ещё по точке -т.о. получить 4 точки. Проблема в том, что двигаться по х надо неравномерно (т.к. производная от sin, по которой изменяется прирост y - cos, а не прямая) если тебе нужно выдерживать постоянную длину штриха.

polopok 05.10.2015 06:03

Ответ: Пунктирная окружность
 
Функция окружность пунктиром с регулируемым шагом .
DarkInside , если у тебя не получилось , то посмотри этот

Код под спойлером :

Код:

Function StepCircle(Point_X# ,Point_Y# ,Radius# = 1,Offset = 4 , rr% = 255 ,gg% = 255 ,bb% = 255)
    Local angle = 0 , trigger
    If Offset < 1 Offset = 1
    While  angle  < 360
        If trigger
            For thisAngle# = angle  To angle  +Offset  Step 0.1
                x# = Radius * Cos (thisAngle) + Point_X#
                y# = Radius * Sin (thisAngle) + Point_Y#   
                WritePixel x,y, (rr*$10000+gg*$100+bb)
            Next
        EndIf
        angle  = angle  + Offset 
        trigger = Not trigger
    Wend
End Function


DarkInside 06.10.2015 10:17

Ответ: Пунктирная окружность
 
polopok, да я уже вроде как написал самопальную функцию. Но спасибо, посмотрю.

moka 06.10.2015 23:22

Ответ: Пунктирная окружность
 
Вот смотри, код доступен, рендер есть (ничего не нужно запускать, 1 клик по ссылке), кто хочет сейчас может код обновить и выложить ссылку на его ввариант. Удобно же!

Пунктирная окружность с регулируемым градусом дуги:
http://jsfiddle.net/bq6vvqch/

И еще версия с гарантированной последовательностью отступ > дуга, и чтобы не было где-то одного мелкого/большого отступа.
Также анимировано: http://jsfiddle.net/o8xkde88/1/

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

PHP код:

var canvas document.getElementById('render');
var 
ctx canvas.getContext('2d');

// step of 15 degrees in radians
var step / (180 Math.PI);

for(var 
0Math.PI step+= 2) {
    var 
step;
    
ctx.beginPath();
    
ctx.arc(canvas.width 2canvas.height 2canvas.width 8astepfalse);
    
ctx.stroke();



polopok 07.10.2015 04:30

Ответ: Пунктирная окружность
 
ага ,нормально ...
Да ,вот что, в приведённой мною функции ,переменную offset проверить ,что она меньше длины круга (2 * Pi * Radius ).

DarkInside 07.10.2015 10:41

Ответ: Пунктирная окружность
 
Всем спасибо за примеры. За ссылку на сервис отдельное спасибо, удобная вещь.

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


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

vBulletin® Version 3.6.5.
Copyright ©2000 - 2024, Jelsoft Enterprises Ltd.
Перевод: zCarot