Author Topic: Разделение отрезка на заданное число равных частей  (Read 2958 times)

0 Members and 1 Guest are viewing this topic.

Aleksandr123

  • Зашел в гости
  • *
  • Posts: 8
    • View Profile
Нужна помощь правильного деления отрезка на равные части, мой вариант $i_4=INT($var2/($i_3+$i_1))  при увеличении длины принимает не правильную форму, [/img]
Code: (clickermann) [Select]
$x1 = 10
$y1 = 10
$x2 = 20
$y2 = 30

if($x1<$x2 & $y1<$y2 & $y2>=$x2)     // направление с верху в низ   $y2>$x2
   $x2=$x2+$x1
   $y2=$y2+$y1

   $var1=$x2-$x1                    // количество рх длина
   $var2=$y2-$y1                    // колличество рх высота
   
   $i_1=INT($var2/$var1) 
   $i_3=$var2-($i_1*$var1) 
   $i_4=INT($var2/($i_3+$i_1))   
   $i_5=INT($var1/$i_3)


   for($i=0, $i<$var1)
      $i_2=0
      while($i_2<$i_1)
          PXLREPLACE ($x1,$y1, $x1,$y1, -1, 0)
          $y1=$y1+1
          $i_2=$i_2+1
      end_cyc
     
      if(($i==$i_4-1 & $i_4!=0))   
  if($i_3>0)
             PXLREPLACE ($x1,$y1, $x1,$y1, -1, 0)
             $y1=$y1+1
             $i_3=$i_3-1
         end_if
         $i_4=$i_4+$i_5
      end_if
         
      $i++
      x1=$x1+1
   end_cyc   
   SCREENSHOT 
end_if
 
WNDBUMP (WNDFIND ("Clickermann - New Script"))
WAIT (600)

Vint

  • Супермодератор
  • Герой форума
  • *
  • Posts: 3935
  • Лечу куда хочу. cman 4.13.014x32, 4.14.003 W10
    • View Profile
Что здесь происходит?
Зачем эти строки
Code: (clickermann) [Select]
   $x2=$x2+$x1
   $y2=$y2+$y1

Здесь неправильный синтаксис, не хватает скобок вокруг каждого выражения (может новый математический блок в 4.13 и разрешает это я не в курсе)
Code: (clickermann) [Select]
if($x1<$x2 & $y1<$y2 & $y2>=$x2)
У нас не C++, такого синтаксиса нет
Code: (clickermann) [Select]
$i++
Пропущен символ $ обозначающий переменную
Code: (clickermann) [Select]
x1=$x1+1

Ну и наконец.
Code: (clickermann) [Select]
   $i_1=INT($var2/$var1)
   $i_3=$var2-($i_1*$var1)
   $i_4=INT($var2/($i_3+$i_1))
   $i_5=INT($var1/$i_3)
Даже не стал вчитываться, но если мы что-то вычисляем (соотношение), его округляем INT, вычисляем-округляем и т.д. В итоге у нас накапливается дикая ошибка. Зачем всё округлять на промежуточных шагах?

Зачем вообще такие сложности. Мы в первом условии всё отсекли. Осталось 1- слева сверху, 2 - справа снизу
($y2>=$x2 - это что вообще такое?)
так зачем мы вычисляем всякие соотношения длины по x к высоте по y? Что это там за вычисления идут.
« Last Edit: September 03, 2018, 06:01:15 PM by Vint »


Aleksandr123

  • Зашел в гости
  • *
  • Posts: 8
    • View Profile
Code: (clickermann) [Select]
if(($x1<$x2) & ($y1<$y2) & ($y2>=$x2))     // обозначение направления когда  высота больше длинны $y2 > $x2
Code: (clickermann) [Select]
$x2=$x2+$x1                             //отступ от края х1,y1 на заданное кол-во px
$y2=$y2+$y1
Code: (clickermann) [Select]
$var1=$x2-$x1                    // колличество рх длина
$var2=$y2-$y1                    // колличество рх высота
   
Code: (clickermann) [Select]
$i_1=INT($var2/$var1)            // высота делится на ширину, $i_1= кол-во шагов
$i_3=$var2-($i_1*$var1)         // вычисление на сколько высота больше длины     
   
Code: (clickermann) [Select]
$i_4=INT($var2/$i_3)   // если высота больше ширины добавить $у2 px по высоте
Code: (clickermann) [Select]
$i_5=INT($var1/$i_3)   // добавлять $y1=$y1+1 через $i_5 шагов 
Проблема в расчете шагов $i_5 
Когда высота превышает длину на 50%,  шаг  $i_5  округляется до 1, и то расстояние которое превышает длину $i_4 прибавляется сразу, не получается распределить правильно $i_5  по длине                       
« Last Edit: September 03, 2018, 06:42:24 PM by Aleksandr123 »

dramster

  • Герой форума
  • *****
  • Posts: 1134
    • View Profile
Нужна помощь правильного деления отрезка на равные части, мой вариант $i_4=INT($var2/($i_3+$i_1))  при увеличении длины принимает не правильную форму.

Не много не понятно, что именно не получается - рисование ровного отрезка, или деление его на равные части.

По теме, решил вспомнить уравнение прямой, проходящей через две заданные точки. Ато ранее постоянно какие-то хитрые способы использовались  :-\ .

Из учебника: ($y1-$y2)*$x + ($x2-$x1)*$y + ($x1*$y2-$x2*$y1) = 0 . Где ($x1,$y1) и ($x2,$y2) это известные точки.

Зная к примеру значение $x (оно в промежутке между $x1 и $x2), можем рассчитать $y : $y = (($x1*$y2-$x2*$y1)+($y1-$y2)*$x)/($x1-$x2)
И то же самое с $x = (($x1*$y2-$x2*$y1)+($x2-$x1)*$y)/($y2-$y1)
Если ($x2-$x1)>($y2-$y1) , то наращиваем $x, а переменную $y считаем по формуле. Иначе, ...наоборот.

Все оказалось довольно просто, не считая всяких оптимизаций для отдельных случаев:
Code: (clickermann) [Select]
$x1 = 10    //наши две точки
$y1 = 10
$x2 = 200
$y2 = 300

PXLREPLACE(0,0,300,300, -1, 16777215)

IF((abs($x2-$x1))>=(abs($y2-$y1)))
   $n = ($x2-$x1)/abs($x2-$x1)
   FOR($x=$x1,$x!$x2+$n,$n)
      $y = ROUND((($x1*$y2-$x2*$y1)+($y1-$y2)*$x)/($x1-$x2),0)
      PXLREPLACE ($x,$y,$x,$y, -1, 0)
   end_cyc
ELSE
   $n = ($y2-$y1)/abs($y2-$y1)
   FOR($y=$y1,$y!$y2+$n,$n)
      $x = ROUND((($x1*$y2-$x2*$y1)+($x2-$x1)*$y)/($y2-$y1),0)
      PXLREPLACE ($x,$y,$x,$y, -1, 0)
   end_cyc
END_IF

SCREENSHOTEX(0,0,300,300, "Image_", 0)

halt

Единственно, что одну точку поставить не выйдет, то есть (($x2-$x1)!0)&(($y2-$y1)!0) . Проще - эти две точки не должны быть одной.



Демонстрация рисования рандомных отрезков в области:
Code: (clickermann) [Select]
PXLREPLACE(0,0,300,300, -1, 16777215)

FOR($a=0,$a<30)
   $x1 = 0
   $y1 = 0
   $x2 = 0
   $y2 = 0
   WHILE((($x2-$x1)=0)&(($y2-$y1)=0))
      $x1 = rnd(0,300)
      $y1 = rnd(0,300)
      $x2 = rnd(0,300)
      $y2 = rnd(0,300)
   END_CYC
   
   
   IF((abs($x2-$x1))>=(abs($y2-$y1)))
      $n = ($x2-$x1)/abs($x2-$x1)
      FOR($x=$x1,$x!$x2+$n,$n)
         $y = ROUND((($x1*$y2-$x2*$y1)+($y1-$y2)*$x)/($x1-$x2),0)
         PXLREPLACE ($x,$y,$x,$y, -1, 0)
      end_cyc
   ELSE
      $n = ($y2-$y1)/abs($y2-$y1)
      FOR($y=$y1,$y!$y2+$n,$n)
         $x = ROUND((($x1*$y2-$x2*$y1)+($x2-$x1)*$y)/($y2-$y1),0)
         PXLREPLACE ($x,$y,$x,$y, -1, 0)
      end_cyc
   END_IF
   
END_CYC

SCREENSHOTEX(0,0,300,300, "Image_", 0)
halt






А насчет деления отрезка на равные части, тут я думаю проблем не должно быть.
« Last Edit: September 06, 2018, 12:09:51 AM by dramster »

Aleksandr123

  • Зашел в гости
  • *
  • Posts: 8
    • View Profile
Нужна помощь правильного деления отрезка на равные части, мой вариант $i_4=INT($var2/($i_3+$i_1))  при увеличении длины принимает не правильную форму.

Не много не понятно, что именно не получается - рисование ровного отрезка, или деление его на равные части.

По теме, решил вспомнить уравнение прямой, проходящей через две заданные точки. Ато ранее постоянно какие-то хитрые способы использовались  :-\ .

Из учебника: ($y1-$y2)*$x + ($x2-$x1)*$y + ($x1*$y2-$x2*$y1) = 0 . Где ($x1,$y1) и ($x2,$y2) это известные точки.

Зная к примеру значение $x (оно в промежутке между $x1 и $x2), можем рассчитать $y : $y = (($x1*$y2-$x2*$y1)+($y1-$y2)*$x)/($x1-$x2)
И то же самое с $x = (($x1*$y2-$x2*$y1)+($x2-$x1)*$y)/($y2-$y1)
Если ($x2-$x1)>($y2-$y1) , то наращиваем $x, а переменную $y считаем по формуле. Иначе, ...наоборот.

Все оказалось довольно просто, не считая всяких оптимизаций для отдельных случаев:
Code: (clickermann) [Select]
$x1 = 10    //наши две точки
$y1 = 10
$x2 = 200
$y2 = 300

PXLREPLACE(0,0,300,300, -1, 16777215)

IF((abs($x2-$x1))>=(abs($y2-$y1)))
   $n = ($x2-$x1)/abs($x2-$x1)
   FOR($x=$x1,$x!$x2+$n,$n)
      $y = ROUND((($x1*$y2-$x2*$y1)+($y1-$y2)*$x)/($x1-$x2),0)
      PXLREPLACE ($x,$y,$x,$y, -1, 0)
   end_cyc
ELSE
   $n = ($y2-$y1)/abs($y2-$y1)
   FOR($y=$y1,$y!$y2+$n,$n)
      $x = ROUND((($x1*$y2-$x2*$y1)+($x2-$x1)*$y)/($y2-$y1),0)
      PXLREPLACE ($x,$y,$x,$y, -1, 0)
   end_cyc
END_IF

SCREENSHOTEX(0,0,300,300, "Image_", 0)

halt

Единственно, что одну точку поставить не выйдет, то есть (($x2-$x1)!0)&(($y2-$y1)!0) . Проще - эти две точки не должны быть одной.



Демонстрация рисования рандомных отрезков в области:
Code: (clickermann) [Select]
PXLREPLACE(0,0,300,300, -1, 16777215)

FOR($a=0,$a<30)
   $x1 = 0
   $y1 = 0
   $x2 = 0
   $y2 = 0
   WHILE((($x2-$x1)=0)&(($y2-$y1)=0))
      $x1 = rnd(0,300)
      $y1 = rnd(0,300)
      $x2 = rnd(0,300)
      $y2 = rnd(0,300)
   END_CYC
   
   
   IF((abs($x2-$x1))>=(abs($y2-$y1)))
      $n = ($x2-$x1)/abs($x2-$x1)
      FOR($x=$x1,$x!$x2+$n,$n)
         $y = ROUND((($x1*$y2-$x2*$y1)+($y1-$y2)*$x)/($x1-$x2),0)
         PXLREPLACE ($x,$y,$x,$y, -1, 0)
      end_cyc
   ELSE
      $n = ($y2-$y1)/abs($y2-$y1)
      FOR($y=$y1,$y!$y2+$n,$n)
         $x = ROUND((($x1*$y2-$x2*$y1)+($x2-$x1)*$y)/($y2-$y1),0)
         PXLREPLACE ($x,$y,$x,$y, -1, 0)
      end_cyc
   END_IF
   
END_CYC

SCREENSHOTEX(0,0,300,300, "Image_", 0)
halt






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

У меня все просто, написал без формул как начинающий, я эту ошибку исправлю !!!
Добавил функцию ARRSORT не сортирует массив правильно
Code: (clickermann) [Select]
Print($Line_x[$i_1],"   1")                                 
if ($i_1=ARRSIZE($Line_x)-1)
  Print ("функция_ARRSORT")
  ARRSORT ($Line_x)
  $i_10=1
  while($i_10<=ARRSIZE($Line_x)-1 & $i_1=ARRSIZE($Line_x)-1)
     Print($Line_x[$i_10],"   2")
     $i_10=$i_10+1
  end_cyc
end_if

dramster

  • Герой форума
  • *****
  • Posts: 1134
    • View Profile
А ведь Aleksandr123 прав. Arrsort действительно нихера не работает  :-\.  За столько времени никто не заметил... значит не сильно эта сортировка и нужна была  :-\

Пример из справки, но с двузначными и однозначными числами одновременно:
Code: (clickermann) [Select]
// генерация массива
for($a=0, $a<10)
   $var[$a] = rnd(0,50)
   print($var[$a])
end_cyc

// сортировка
arrsort($var)
print("sort:")

// вывод результата
for($a=0, $a<10)
   print($var[$a])
end_cyc

halt

Лог говорит сам за себя:
Code: (текст) [Select]
16:23:35 6
16:23:35 19
16:23:35 23
16:23:35 11
16:23:35 46
16:23:35 9
16:23:35 18
16:23:35 46
16:23:35 3
16:23:35 39
16:23:35 sort:
16:23:35 11
16:23:35 18
16:23:35 19
16:23:35 23
16:23:35 3
16:23:35 39
16:23:35 46
16:23:35 46
16:23:35 6
16:23:35 9



dramster

  • Герой форума
  • *****
  • Posts: 1134
    • View Profile
У меня все просто, написал без формул как начинающий, я эту ошибку исправлю !!!
Просто?  :o . Я минут 15 пытался вникнуть что там к чему...
 А не мог бы ты немного прокомментировать свой код? Интересно как он работает  ::).

Vint

  • Супермодератор
  • Герой форума
  • *
  • Posts: 3935
  • Лечу куда хочу. cman 4.13.014x32, 4.14.003 W10
    • View Profile
Заметили. И писали что не работает. Вот почему не работает в релизе хз.
Для координат тоже пользуюсь своими. Но они медленные. На координаты впрочем хватает обычно.


Aleksandr123

  • Зашел в гости
  • *
  • Posts: 8
    • View Profile
Code: (clickermann) [Select]
$x1 = 10
$y1 = 10
$x2 = 20
$y2 = 30
координаты xy
Code: (clickermann) [Select]
DEFINE ( $Line_x, $x2 )
DEFINE ( $Line_y, $y2 )
DEFINE ( $Line_xy, $y2 )
DEFINE ( $Line, 1 )
DEFINE ( $Line_1, 1)
DEFINE ( $Line_2, 1)
Массивы для сортировки
Code: (clickermann) [Select]
if($x1<$x2 & $y1<$y2 & $y2>=$x2 & $x1>=$y1) $y2>=$x2  линия с верху в низ или горизонтальная
Code: (clickermann) [Select]
$x2=$x2+$x1
$y2=$y2+$y1
Начало линии
Code: (clickermann) [Select]
$var1=$x2-$x1                    // количество рх длина
$var2=$y2-$y1                    // количество рх высота
Code: (clickermann) [Select]
$i_1=INT($var2/$var1)
$i_3=$var2-($i_1*$var1) // количество добавлений по высоте при условии что $y2>$x2
Code: (clickermann) [Select]
$x2 = $x1                    //х2 и у2 приминаются в  функции когда необходимо увеличить на несколько рх по высоте на 1 уровне
$y2 = $y1
Code: (clickermann) [Select]
while($i_3>=0)                       //проверка условия нужно добавить высоту $ i_3 
   if($i_3=1)                            //прибавление по высоте в по 2 циклам, 1 цикл интервал 2,3,4,5,6,9,10
      $i_6=1+INT($var1/2)        //цикл 2 интервал 7,8 прибавлений по высоте       
      $i_7=$i_6                         //$i_7 присваивается интервал между прибавлениям высоты
      else                                  //количество прибавлений не должно больше 20 к примеру 20/9 интервал 3 шага
         $i_6=INT($var1/$i_3)   
if($i_6=1)         
    $i_7=2
         else
            if($i_3=7 | $i_3=8)     //количество прибавлений 20/8 или 20/8  интервал 2 шага, линия изменит угол
       $i_6=3                    //нужно определить интервал больше длины, интервал для 7,8 добавлений по высоте будет равен 3
       $i_7=3                    //в 1 цикле если 8 добавлений, 3*8=24, 24-20=4
            else                            //в цикле 2 нужно определить интервал для 4 прибавления, интервал 20/4=5
               if($i_6=10 & $i_3=2)//для числи 7 и 8 нужны 2 итерации
          $i_7=6
               else
                  $i_7=$i_6
               end_if
            end_if
        end_if
    end_if
//---  
   for($i=0, $i<$var1) //1 цикл интервал 1,2,3,4,5,6,,,9,10 умноженное на количество прибавлений,не превышать цифру 20
                                  // шаг                  10,9,6,5,4,3,2,1
      if($i_4=2)             // если интервал 2 нужно увеличить на 1 для асимметрии линии, к примеру  2 добавления высоты через интервал 10
         $y2=$y2+1       // асимметрия интервал равный 7 при 2 добавлений высоты, я установил 1 что не соответствует асимметрии
      end_if                 
      if($i_4=1)   
         $y2=$y1
         $x2=$x1
         $i_4=2
      end_if     
      $i_2=0
      while($i_2<$i_1 & $i_4=0)      //1 цикл
         ARRPUSH ($Line_x, $x2)      //увеличить размер массива
ARRPUSH ($Line_y, $y2)
$y2=$y2+1
         $i_2=$i_2+1
      end_cyc
      if($i_8<$i_3 & $i=$i_6)           
         if($i=$i_6 & $i_6!=0)
            if($i_3>0)
               ARRPUSH ($Line_x, $x2)
               ARRPUSH ($Line_y, $y2)
               $y2=$y2+1
               $i_3=$i_3-1
            end_if
         $i_6=$i_6+$i_7
         end_if
      $i_8=$i_8+1
      end_if
   $x2=$x2+1
   $i_8=0
   end_cyc
   $i_4=1
   if($i_3=0)
      $i_3=$i_$i_3-1
    end_if
end_cyc

Aleksandr123

  • Зашел в гости
  • *
  • Posts: 8
    • View Profile
Code: (clickermann) [Select]
$i_1 = 1
$i_2 = 1
$i_3 = 1
$i_4 = 1
$i_5 = 1
$i_6 = 1
$i_7
$i_9 = 1

while($i_1<=ARRSIZE($Line_x)-1)                //1
   if($i_4=1)                                                 // заполнение массива значениями из из 1 цикла 
      if($Line_x[$i_1]>=$i_2)                         // если 8 добавлений интервал 3 больше 20 равное 24
         $i_2 = $Line_x[$i_1]                           //массив заполнен в первом цикле до 6 интервал 3,записан в массив 3,6,9,12,15,18,
   else                                                          //добавить 2 если 8 добавлений или 1 при семи добавлениях
         $Line[$i_3] = $Line_x[$i_1]           //записан в массив 3,6,9,12,15,18,6,12
if($i_8<$Line[$i_3])
    $i_8=$Line[$i_3]
else
    if($i_8>=$Line[$i_3])
       $Line_1[$i_9]=$Line[$i_3]
       $i_9=$i_9+1
               INC ($Line_1)
    end_if
end_if
      $i_3=$i_3+1
      INC ($Line)
      end_if
   end_if

   if($i_4=0 )
      $i_8=1
      $i_9=1
      $i_10=1

      while($i_8<=ARRSIZE($Line)-1)                      //1.1
         if($i_9<=ARRSIZE($Line_1)-1)                    //ARRSORT  массив 3,6,9,12,15,18
           if($Line[$i_10]<$Line_1[$i_9])                   //второй массив 6,12
               $Line_y[$i_8]=$Line[$i_10]
       $i_10=$i_10+1
    else
       $Line_y[$i_8]=$Line_1[$i_9]
               $i_9=$i_9+1
    end_if
else
    $Line_y[$i_8]=$Line[$i_10]
            $i_10=$i_10+1
         end_if    
  $i_8=$i_8+1
         if($i_8>ARRSIZE($Line)-1)
            $i_8=1
            while($i_8<=ARRSIZE($Line)-1 )
               INC ($Line_2)
       $Line_2[$i_8]=$Line_y[$i_8]               
               $i_8=$i_8+1
    end_cyc
            $Line_2[$i_8]=0
         end_if
      end_cyc
   end_if   
   $i_7=$i_1                                             //3
   if($i_4=0 & 0<ARRSIZE($Line_2)-1)       //заполнение общий массив $Line_xy ...3,6,6,9,12,12,15,18......
      while($Line_x[$i_7]=$Line_2[$i_3])             
         $i_7=$i_7+1
if($Line_x[$i_7]>$Line_2[$i_3])
    while($i_3<=ARRSIZE($Line_2)-1 & $i_6<=ARRSIZE($Line_x)-1) 
       $Line_xy[$i_6]=$Line_x[$i_5]
               if($Line_xy[$i_6]>$Line_2[$i_3] & $i_4=0)
            $Line_xy[$i_6]=$Line_2[$i_3]
  $i_5=$i_5-1
  $i_4=4
       end_if
   $i_6=$i_6+1
   $i_5=$i_5+1
   if($i_6>ARRSIZE($Line_x)-1)
              $i_6=1
      while($i_6<=ARRSIZE($Line_x)-1)     // заполнение массива поочередно //1//3
                 $Line_x[$i_6]=$Line_xy[$i_6]
           $i_6=$i_6+1
      end_cyc
   end_if
       end_cyc 
       if($i_4=4)
  $i_4=0
  $i_5=1
          $i_6=1
          $i_3=$i_3+1                                       
        end_if
     end_if
   end_cyc
 end_if
 $i_1=$i_1+1
   if($i_1>ARRSIZE($Line_x)-1 & $i_4=1)        //2
      if($i_4=1)                                               //функция завершения первого цикла заполнение массива
$i_1=1
$i_3=1
        $i_9=1
        $i_4=0
      end_if
   end_if
end_cyc

Aleksandr123

  • Зашел в гости
  • *
  • Posts: 8
    • View Profile
Code: (clickermann) [Select]
FOR($y=$y1,$y!$y2+$n,$n)
   $x = ROUND((($x1*$y2-$x2*$y1)+($x2-$x1)*$y)/($y2-$y1),0)
   PXLREPLACE ($x,$y,$x,$y, -1, 0)
end_cyc

$x = (($x1*$y2-$x2*$y1)+($x2-$x1)*$y)/($y2-$y1)
Какой порядке выполнения действий, $x1*$y2-$x2*$y1 с начало все перемножить и вычисть, или по порядку умножить вычесть умножить ?

dramster

  • Герой форума
  • *****
  • Posts: 1134
    • View Profile
Сначала умножение, потом вычитание.

Vint

  • Супермодератор
  • Герой форума
  • *
  • Posts: 3935
  • Лечу куда хочу. cman 4.13.014x32, 4.14.003 W10
    • View Profile
Лог говорит сам за себя:
Code: (текст) [Select]
16:23:35 6
16:23:35 19
16:23:35 23
16:23:35 11
16:23:35 46
16:23:35 9
16:23:35 18
16:23:35 46
16:23:35 3
16:23:35 39
16:23:35 sort:
16:23:35 11
16:23:35 18
16:23:35 19
16:23:35 23
16:23:35 3
16:23:35 39
16:23:35 46
16:23:35 46
16:23:35 6
16:23:35 9
Думаю здесь опять всплыла проблема с типами. Видно же что сортирует в лексиграфическом порядке, т.е. элементы он видит как строки.