Интересная форма

    Хабр, привет. Эта статья не претендует на большую серьезность, я просто хочу поделиться новой формой, которую я открыл. Это такой круг, цвет точек которого равен сумме квадратов координат заданной точки. Другими словами pixel_color=(pixel_x^2+pixel_y^2).toString(16).
    Тут я немного ошибся, правильная функция определения цвета выглядит так:
    function(x, y){
        z = x*x+y*y;
        if(z===0) return '#000000';
        while(z<'0x100000' && z) z=z<<4;
        while(z>'0xffffff' && z) z = Math.floor(z/16);
        return '#'+z.toString(16);
    }

    Т.е циклично добавляется побитовый сдвиг влево на 4 бита (эквивалентно дописыванию 0 в конце) до тех пор пока 16-ричное число не станет шестизначным, что требуется от RGB-модели.Для больших значений используется цикличное деление на 16


    Эта фигура сама собой очень интересна, представляет собой что-то вроде четкого интерферентного фрактала или даже модели вселенной, описывающей микро и макромир. Несмотря на то, что ее легко получить, я нигде не нашел ничего похожего на нее. Возможно я первооткрыватель. В таком случае я хотел бы назвать ее Тетраскоп (tetrascope). В приведенном примере я генерирую тетраскоп радиусом 1024px, максимальное что у меня получилось сгенерировать на своей машине это объект радиусом 4096px, картинка которого весит ~150 мегабайт.

    Эта модель — абсолют, под этим я понимаю, что ее физикоматематическая модель существует сама по себе, еще задолго до своего открытия и независимо от человека, как самодостаточная форма бытия.

    P.S.: картинку рекомендую смотреть на компьютере в 100% масштабе — так более понятно что она из себя представляет. В комментариях я предлагаю поэксперементировать с кодом, предложить свое описание и смысл картинки или ее название, и вообще как-нибудь дополнить этот пост, возможно какой-то информацией.

    $(document).ready(function(){
    	var R=1024; var D=2*R+1;
    	var rgb = function(c){
    		if(c.length<=6)	return c+("0".repeat(6-c.length));
    		else return c.substring(0, 3)+c.substring(c.length-3);
    	}
    	$('body').append('<canvas id="C" width="'+D+'" height="'+D+'">');
    	var canvas = document.getElementById('C');
    	var ctx = canvas.getContext('2d');
    	ctx.fillStyle="#ffffff00";
    	ctx.fillRect(0, 0, 256, 256);
    	for(var x = 0;x<=R;x++) {
    		for(var y = 0;y<=R;y++) {					
    			var X1 = R-x;
    			var Y1 = R-y;
    			var X2 = R+x;
    			var Y2 = R+y;
    			if (( x*x+y*y )   <=   R*R    ) {
    				ctx.fillStyle="#"+(   rgb( (x*x+y*y).toString(16))   );
    				ctx.fillRect(X1, Y1, 1, 1);
    				ctx.fillRect(X1, Y2, 1, 1);
    				ctx.fillRect(X2, Y1, 1, 1);
    				ctx.fillRect(X2, Y2, 1, 1);
    	}	}	}
    });
    
    Ads
    AdBlock has stolen the banner, but banners are not teeth — they will be back

    More

    Comments 51

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

        А что сложного в ее подделке по сравнению с любым другим микроузором?

          0
          Просто, как вариант использования. Я так полагаю микроузоры вообще сложно подделать. И еще их надо нарисовать, а у меня готовый микроузор. Для этой картинки скорее всего понадобится специальный принтер
            0
            Для этой картинки скорее всего понадобится специальный принтер

            Почему не подойдет принтер, на котором печатаются существующие микроузоры?

              0
              я не говорил что не подойдет, главное что цветной.
                0

                Существующие микроузоры вполне себе бывают цветными. Они были цветными на советских рублях в моем детстве.

        +8
        Надо добавить 3-е измерение и посмотреть что получится в 3Д
          0
          Надеюсь, сможет кто-нибудь сделать, я в 3D не силен.
            +2

            Может попробую на C# или Kotlin забабахать демку.

              0
              Было бы очень круто.
            0
            Мысленный эксперимент без 3D принтера показывает, что получится эллиптический параболоид)
            +4
            Ух ты ж, блин. Тетраскоп.
              +5
              Подождите, если длина произведения (в hex) выходит больше 6, то Вы берёте первые три цифры и последние три. Выходит, что красная компонента и старшая часть зелёной кодируют одно, а младшая часть зелёной и синяя — другое. Зачем так? Тем более, что для радиуса менее 4096 произведение всё равно меньше, чем #ffffff.

              И ещё дополняете нулями не слева, как это было бы более логично, а справа. Если дополнять нулями слева, то выходит иначе, и на радиусе 1024 почти без красного, потому что максимальное значение — #0FF801, (0xFF * 0xFF).

              R=1024, дополнение нулями слева
              image
                0
                ну эта часть не используется в программе, я ввел ее чтоб была на запасной случай.
                  0
                  про c вы — правы. наверное из-за этой маленькой ошибки и получается Тетраскоп.
                    0
                    ну, у Вас на картинке получается их несколько, вложенных друг в друга (с радиусами 4, 16, 64, 1024), которые до 1, 2, 3 и 4 цифр в hex-квадрате.
                      0
                      Можно ли картинку считать абсолютом? Мне кажется попиксельная прорисовка интерференции волн совершенна, для того чтобы быть человеческим творением, — т.е. я скорее открыл нежели создал эту форму.
                        +3
                        Там нет никакой интерференции. С бесконечным разрешением это были бы просто концентрические круги (поскольку по факту цвет точки зависит от расстояния до центра, точнее, квадрата расстояния). Но именно наложение пиксельной сетки даёт красивые дополнительные окружности.
                  +2
                  Как же все же интересно экспериментировать, получать результат и видеть его. Но подгонять результат под красивый и желаемый — уже не так интересно, как было заявлено. А так да, можно фракталами строить довольно красивые и сложные фигуры.

                  Удачи с дальнейшими экспериментами!
                    0

                    Напомнило искажение горизонта событий, но уже на больших масштабах иллюзия уплотнения этих концентрических окружностей исчезла
                    image

                    +3
                      0
                      Почему-то, увы, Shadertoy меня не хочет регистрировать, но я добавил поддержку масштаба с опциональным уменьшением со временем и поддержку первых трёх/последних трёх hex-цифр для чисел больше 0xFFFFFF:

                      Код шейдера
                      void mainImage( out vec4 fragColor, in vec2 fragCoord )
                      {
                          vec2 coord = fragCoord - (iResolution.xy/vec2(2.0));
                          
                          float factor = 50.0;
                          
                          // WARNING: weird zooming out
                          factor = float(int(iTime*25.0) + 1) / 5.0;
                          
                          coord *= factor;
                          int x = int(coord.x);
                          int y = int(coord.y);
                      
                          int a = x*x + y*y;
                      
                          // WARNING: flashing
                          // a += int(iTime * 5000.0);
                          // a -= int(iTime * 1000.0);
                      
                          // emulating JS: a.toString(16) + "0".repeat(6 - a.toString(16).length)
                          if (a < 0x100000) a = a << 4;
                          if (a < 0x100000) a = a << 4;
                          if (a < 0x100000) a = a << 4;
                          if (a < 0x100000) a = a << 4;
                          if (a < 0x100000) a = a << 4;
                          
                          // emulating JS: c.substring(0, 3) + c.substring(c.length-3);
                          while (a > 0xFFFFFF) {
                              a = ((a ^ (a & 0xFFF)) >> 4) | (a & 0xFFF);
                          }
                          
                          fragColor = vec4(
                              float((a >> 16) & 255) / 255.0,
                              float((a >>  8) & 255) / 255.0,
                              float((a >>  0) & 255) / 255.0,
                              1.0
                          );
                      }
                      

                        0
                        У вас как-то не так анимация работает, но сам поправить ошибку не могу
                          +1
                          Анимация движения, еще есть строчка a += int(iTime * 1000.0);, можете с ней поиграться

                          Код шейдера
                          void mainImage( out vec4 fragColor, in vec2 fragCoord )
                          {
                              vec2 size = iResolution.xy;
                              
                              float speed_fly = 150.0;
                              
                              size = vec2(iTime * speed_fly);
                              
                              vec2 coord = fragCoord - (size.xy/vec2(2.0));
                              
                            //  float factor = 50.0;
                              
                              // WARNING: weird zooming out
                            //  factor = float(int(iTime*25.0) + 1) / 5.0;
                          
                              int x = int(coord.x);
                              int y = int(coord.y);
                              
                              int a = x*x + y*y;
                              
                              //a += int(iTime * 1000.0);
                          
                              // WARNING: flashing
                              // a += int(iTime * 5000.0);
                              // a -= int(iTime * 1000.0);
                          
                              // emulating JS: a.toString(16) + "0".repeat(6 - a.toString(16).length)
                              if (a < 0x100000) a = a << 4;
                              if (a < 0x100000) a = a << 4;
                              if (a < 0x100000) a = a << 4;
                              if (a < 0x100000) a = a << 4;
                              if (a < 0x100000) a = a << 4;
                              
                              // emulating JS: c.substring(0, 3) + c.substring(c.length-3);
                              while (a > 0xFFFFFF) {
                                  a = ((a ^ (a & 0xFFF)) >> 4) | (a & 0xFFF);
                              }
                              
                              fragColor = vec4(
                                  float((a >> 16) & 255) / 255.0,
                                  float((a >>  8) & 255) / 255.0,
                                  float((a >>  0) & 255) / 255.0,
                                  1.0
                              );
                          }

                        +5
                        Получил когда-то похожую конфигурацию при расчёте объёмов ячеек трёхмерной прямоугольной сетки, отсекаемых поверхностью полусферы:

                        image

                        Похоже, такая структура — результат взаимодействия окружности (сферы) с ортогональной решёткой. Главное тут — найти эффектный способ визуализации, чтобы проявилась структура
                          0
                          Вот что еще видно с моей картинки — пересечение четырех высот.
                          И походу с медианами и биссектриссами та же фигня, только менее отчетливо.
                          image
                            +4
                            Здесь же на хабре, кажется, где-то была статья про алгоритмы ресемплинга изображений, где в качестве тестового изображения использовали картинку с zone plate. Разные алгоритмы ресемплинга приводили к таким же «фрактальным» артефактам из-за алиасинга. Что-то вроде такого:

                            image
                            +2
                            Если начало координат в центре окружности, то x^2+y^2 — это расстояние от центра. Для всех точек на одной окружности вы должны были получить одинаковый цвет. Это вы в коде что-то нахимичили.
                              +1
                              Мне больше всего интересно, можно ли с этой картинки считать ее звук? Выглядит так как будто можно, но способ я не знаю.
                                +3
                                Угу, а ещё неплохо бы ауру считать. Она наверняка какая-то необычная получится.
                                  –1
                                  Я сделал штуку для этого дела, чтоб послушать картинку в разных местах, замена RGB-видению:
                                  красный: частота 768-512; синий: частота: 512-256; зеленый: частота 256-0
                                  $('#C').on('mousemove touchmove', function(e){
                                  		if (Tone.context.state !== 'running') {
                                  			Tone.context.resume();
                                  			synth = new Tone.PolySynth().toDestination();
                                  			window.synth = synth;
                                  			if ((typeof si) === 'undefined') {				
                                  				mr = 0.1;
                                  				si = setInterval(function(){					
                                  					X = Math.abs(window.e.pageX-1024);
                                  					Y = Math.abs(window.e.pageY-1024);
                                  					if (X*X+Y*Y>R*R) return;
                                  					memory = new Array(); n=0;
                                  					memory.push( Math.floor( Math.abs(   Number.parseInt( rgb((X*X+Y*Y).toString()).substring(0,2), 16 )+512  ) ) );
                                  					memory.push( Math.floor( Math.abs(   Number.parseInt( rgb((X*X+Y*Y).toString()).substring(2,4), 16 )+256  ) ) );
                                  					memory.push( Math.floor( Math.abs(  Number.parseInt( rgb((X*X+Y*Y).toString()).substring(4,6), 16 )+0  ) ) );
                                  					synth.triggerAttackRelease([memory[n], memory[n+1], memory[n+2]], Tone.now(), 0, 0.125);
                                  				}, 128);
                                  			}
                                  		}
                                  	});
                                  	$(document).mousemove(function(e){
                                  		window.e = e;
                                  	});
                                +1
                                модели вселенной, описывающей микро и макромир
                                А можно подробнее? Это как? И это тоже не понятное утверждение:
                                Эта модель — абсолют, под этим я понимаю, что ее физикоматематическая модель существует сама по себе, еще задолго до своего открытия и независимо от человека, как самодостаточная форма бытия
                                  –2
                                  1. Лично я вижу в этой форме целую галактику с черной дырой по центру и массивные объекты излучающие гравитационные волны, на нижних уровнях описывается микромир, на высших — макро, отчетливо видно 4 оси симметрии x=0,y=0, x=y и x=-y. У каждой точки есть три такие же относительно осей симметрии. Это как суперпозиция во множествах X, Y, Z, T, где последнее время. И отчетливо видны углы под 30, 60 и 90 градусов, как для стрелок на часах.
                                  2. Посмотри на нее еще раз, модель является очень сложной для элементарной формулы и содержит даже такие визуализации как пересечение высот в конкретной точке, или сетчатость — это не потому, что я сделал ее такой, а потому что она такой была.
                                    0
                                    Я и в синусоиде это вижу…
                                      0
                                      Синусоида это прекрасно. Мой объект тоже повторяет себя в бесконечности.
                                        0
                                        … и мы не создали её, она уже была до нас.
                                    +1
                                    Наверное имеется ввиду самоподобие обозримой вселенной, микро и макро мира.

                                    См. книгу «Фрактальная геометрия природы» Б. Мандельброта,
                                    обзор его доклада на конференции TED:
                                    Бенуа Мандельброт на TED: «Фракталы и искусство изломов»
                                    а также статью
                                    Созерцание великого фрактального подобия


                                    Сама мысль то не нова. Однако, чтобы убедиться в том, что эта «модель» скажем так «вездесуща», нужны хоть какие-то исследования. Ведь, как правило, на основе модели можно делать «предсказания». Т.е. вот если на модели так, то в реальном мире будет так. И проверить, а действительно ли это так.
                                    Без такой проверки это всего лишь «математическая лирика»: мечта о том, что все разнообразие в мире основано на одной единственной элементарной формуле.
                                    +2
                                    Писали визуализацию, по пути сделали ошибочку, получилась непонятная фигня — открыли структуру вселенной.

                                    Вы бы ещё сказали что формула y^4-x^4=xy доказывает превосходство белой расы.
                                      0
                                      Ваш код не запустился из консоли в FireFox скорее всего из за использования внешних библиотек,
                                      я минимально изменил его:
                                      1. $(document).ready(function(){});
                                        //заменил на
                                        (function(){})();
                                        //что за скобки? https://developer.mozilla.org/ru/docs/Словарь/IIFE
                                        
                                      2. $('body').append('<canvas id="C" width="'+(R*2)+'" height="'+(R*2)+'">');
                                        //заменил на
                                        document.body.innerHTML=('<canvas id="C" width="'+(R*2)+'" height="'+(R*2)+'"></canvas>');
                                        //appendChild() требовал больше изменений, document.write() запускался только поверх открытой страницы но не "новой вкладки"

                                      Код с дополнениями
                                      (function(){
                                      	var R=1024; var D=2*R;
                                      	var rgb = function(c){
                                      		if(c.length<=6)	return c+("0".repeat(6-c.length));
                                      		else return c.substring(0, 3)+c.substring(c.length-3);
                                      	}
                                      	document.body.innerHTML=('<canvas id="C" width="'+(R*2)+'" height="'+(R*2)+'"></canvas>');
                                      	var canvas = document.getElementById('C');
                                      	var ctx = canvas.getContext('2d');
                                      	ctx.fillStyle="#ffffff00";
                                      	ctx.fillRect(0, 0, 256, 256);
                                      	for(var x = 0;x<D;x++) {
                                      		for(var y = 0;y<D;y++) {					
                                      			var X1 = R-x;
                                      			var Y1 = R-y;
                                      			var X2 = R+x;
                                      			var Y2 = R+y;
                                      			if (( x*x+y*y )   <=   R*R    ) {
                                      				ctx.fillStyle="#"+(   rgb( (x*x+y*y).toString(16))   );
                                      				ctx.fillRect(X1, Y1, 1, 1);
                                      				ctx.fillRect(X1, Y2, 1, 1);
                                      				ctx.fillRect(X2, Y1, 1, 1);
                                      				ctx.fillRect(X2, Y2, 1, 1);
                                      	}	}	}
                                      })();


                                      Живой пример на jsfiddle.net/6wk2oe40
                                        0
                                        Мне тут скинули тетраскоп на python (человек не может зарегистрироваться)
                                        pastebin.com/h9rzbWQc
                                          0
                                          хрусталик вообще я помешался на этой форме — в ней есть всё и ничто. можно рассмотреть что угодно. так понятно и так непонятно. если для вас это не так загадычно, попробуйте ответить на вопрос: откуда там вибрирующие пузырьки?
                                          0
                                          Я немного поторопился со статьей и в первоначальном варианте было немного не точное описание алгоритма, и внес правки в код, из-за которого исходное изображение немного сдвинуто вправо-вниз на один пиксель.
                                            0
                                            Выкладываю свой код тетраскопа для Go
                                            package main
                                            
                                            import (
                                                "image"
                                                "image/color"
                                                "image/draw"
                                                "image/png"
                                                "os"
                                                 "strings"
                                                "strconv"
                                                //"fmt"
                                            )
                                            
                                            func ConvertToColor(s string) (r string) {
                                                r = s
                                                if len(s)<6 {
                                                    r = s+strings.Repeat("0", 6-len(s))
                                                } else if len(s)>6 {
                                                    r = string(s[0:6])
                                                }
                                                return r
                                            }
                                            
                                            func ParseHexColorFast(s string) (c color.RGBA) {
                                                c.A = 0xff
                                            
                                                if s[0] != '#' {
                                                    return c
                                                }
                                            
                                                hexToByte := func(b byte) byte {
                                                    switch {
                                                    case b >= '0' && b <= '9':
                                                        return b - '0'
                                                    case b >= 'a' && b <= 'f':
                                                        return b - 'a' + 10
                                                    case b >= 'A' && b <= 'F':
                                                        return b - 'A' + 10
                                                    }
                                                    return 0
                                                }
                                                c.R = hexToByte(s[1])<<4 + hexToByte(s[2])
                                                c.G = hexToByte(s[3])<<4 + hexToByte(s[4])
                                                c.B = hexToByte(s[5])<<4 + hexToByte(s[6])
                                                return
                                            }
                                            
                                            func main() {
                                                
                                                R:=1024
                                                D:=R*2    
                                                new_png_file := "tetrascope.png"
                                                
                                                myimage := image.NewRGBA(image.Rect(0, 0, D, D))
                                                bgcolor := color.RGBA{0, 0, 0, 0}
                                                draw.Draw(myimage, myimage.Bounds(), &image.Uniform{bgcolor}, image.ZP, draw.Src)
                                            
                                                for x:=0; x<R; x++ {
                                                    for y:=0; y<R; y++ {
                                                        x1 := R-x-1
                                                        x2 := R+x-1
                                                        y1 := R-y-1
                                                        y2 := R+y-1
                                                        if x*x+y*y <= R*R {
                                                            var c int64;                
                                                            c = int64(x*x+y*y);
                                                            col := "#"+ConvertToColor(strconv.FormatInt(c, 16))
                                                            //fmt.Println(col, x, y)
                                                            color := ParseHexColorFast(col)
                                                            pixel1 := image.Rect(x1, y1, x1+1, y1+1)
                                                            pixel2 := image.Rect(x1, y2, x1+1, y2+1)
                                                            pixel3 := image.Rect(x2, y1, x2+1, y1+1)
                                                            pixel4 := image.Rect(x2, y2, x2+1, y2+1)
                                                            draw.Draw(myimage, pixel1, &image.Uniform{color}, image.ZP, draw.Src)
                                                            draw.Draw(myimage, pixel2, &image.Uniform{color}, image.ZP, draw.Src)
                                                            draw.Draw(myimage, pixel3, &image.Uniform{color}, image.ZP, draw.Src)
                                                            draw.Draw(myimage, pixel4, &image.Uniform{color}, image.ZP, draw.Src)
                                                        }
                                                    }   
                                                }
                                            
                                                myfile, err := os.Create(new_png_file)     // ... now lets save imag
                                                if err != nil {
                                                    panic(err)
                                                }
                                                png.Encode(myfile, myimage)   // output file /tmp/two_rectangles.png
                                            }

                                            Работает быстрее чем на js, и в перспективе можно получать изображения большего масштаба, так как нет браузерных ограничений.

                                            Only users with full accounts can post comments. Log in, please.