2015년 12월부터 만들기 시작한 시간표 프로그램.

수강신청을 할 때 선택한 과목의 시간을 바로바로 알 수 있는 웹페이지이다.

과목코드, 과목명, 교수님 검색이 가능하며 이미지저장기능과 공유기능이 있다.

아직 전체적으로 미완성인 상태이며 점차 새로운 기능을 추가할 계획... 


Javascript, jQuery3, Ajax 사용.


사이트 주소 : http://hanpyo.com

소스코드 : https://github.com/zetagate/hanpyo (라이센스 : GPL v3)






xor연산자를 사용하여 Javascript로 canvas에 간단한 패턴 이미지를 그려보았다.


   for(var i=0; i<height; i++) {

     for(var j=0; j<width; j++) {

       pixels[i*width + j] = (i^j)%256;

     }

   } 






xor연산자 대신 atan2()함수를 사용한 결과


    for(var i=0; i<height; i++) {

        for(var j=0; j<width; j++) {

            var dist = getDist(j-width/2, i-height/2);  //거리

            var dir = getDir(j-width/2, i-height/2);  //각도

            pixels[i*width + j] = (256-dist)/(dir/96);

        }

    } 




전체 소스코드 : https://github.com/tibyte/visual/tree/master/xor





보로노이 다이어그램을 이용하여 오각형 Type 5 테셀레이션을 그려보았다.


(1) 사잇각이 60도인 기준점들을 찍는다.


(2) 기준점을 중심으로 하여 일정한 각도로 6개의 시드 점을 찍는다.


(3) 시드점을 기준으로 시드점에서 가장 가까운 거리에 있는 픽셀들끼리 묶어서 평면을 분할한다. 


(4) 완성된 테셀레이션





소스코드

https://github.com/tibyte/visual/blob/master/tessellation

캔버스의 크기가 작아서 외접원을 구하지 않고 단순 반복문으로 구현...

var ctx;
var width;
var height;
var pixels = [];
var points = [];
var numPoints = 0;
function init()
{
canvas = document.getElementById("canvas");
ctx = canvas.getContext("2d");
width = canvas.width;
height = canvas.height;
for(var i=0; i<height; i++) {
for(var j=0; j<width; j++) {
pixels[i*width + j] = 0;
}
}
for(var i=0; i<10; i++) {
for(var j=0; j<10; j++) {
var cx = j*80-100;
var cy = i*92+j*46-250;
for(var k=0; k<6; k++) {
points[numPoints] = {};
points[numPoints].x = cx + 36*Math.cos(k*Math.PI/3+11/180*Math.PI);
points[numPoints].y = cy + 36*Math.sin(k*Math.PI/3+11/180*Math.PI);
var rr = (points[numPoints].y+points[numPoints].x)/8;
var rg = (points[numPoints].y*2+points[numPoints].x*4)/8;
var rb = (points[numPoints].y*4+points[numPoints].x*8)/8;
rr = Math.floor(rr);
rg = Math.floor(rg);
rb = Math.floor(rb);
points[numPoints].c = "rgb("+rr+","+rg+","+rb+")";
++numPoints;
}
}
}
fill(ctx);
edge(ctx);
//point(ctx);
}
function fill(ctx)
{
for(var i=0; i<height; i++) {
for(var j=0; j<width; j++) {
var min = width*width+height*height;
var minK = 0;
for(var k=0; k<numPoints; k++) {
var dy = i-points[k].y;
var dx = j-points[k].x;
var dist = dx*dx+dy*dy;
if(dist < min) {
min = dist;
minK = k;
}
}
pixels[i*width + j] = points[minK].c;
ctx.fillStyle = points[minK].c;
ctx.fillRect(j, i, 1, 1);
}//end j loop
}
}
function edge(ctx)
{
for(var i=0; i<height; i++) {
for(var j=0; j<width; j++) {
if(pixels[i*width + j] != pixels[i*width + j-1] ||
pixels[i*width + j] != pixels[i*width + j+1] ||
pixels[i*width + j] != pixels[(i-1)*width + j] ||
pixels[i*width + j] != pixels[(i+1)*width + j]) {
ctx.fillStyle = "#000000";
ctx.fillRect(j, i, 1, 1);
}
}
}
}
function point(ctx)
{
for(var k=0; k<numPoints; k++) {
console.log("aa");
ctx.fillStyle = "#000000";
ctx.fillRect(points[k].x, points[k].y, 2, 2);
}
}

 






인터넷 익스플로러 9 이상에서 보일겁니다. (모바일에선 잘 안됩니다)


 





펄린노이즈(perlin noise)를 연습하다가 나온 실패작(?).

아래에 코드(ActionScript3.0)가 있지만 펄린노이즈 코드는 아닙니다.

그래도 그냥 올려봅니다...







package
{
    import flash.display.Bitmap;
    import flash.display.BitmapData;
    import flash.display.Sprite;
    import flash.events.Event;
    import flash.geom.Rectangle;
    import flash.geom.Vector3D;
    import flash.utils.setInterval;
   
   
    public class Main extends Sprite
    {
       
        public function Main():void
        {
            if (stage) init();
            else addEventListener(Event.ADDED_TO_STAGE, init);
        }
       
        private function init(e:Event = null):void
        {
            removeEventListener(Event.ADDED_TO_STAGE, init);
            // entry point
           
   
            var bd:BitmapData = new BitmapData(500, 500, false);
            var bmp:Bitmap = new Bitmap(bd);   
            bmp.x = bmp.y = 50;
            addChild(bmp);
           
            var vertices:Vector.<Vector.<Vector3D>> = new Vector.<Vector.<Vector3D>>();
            for (var i:int = 0; i < 10; i++) {
                vertices[i] = new Vector.<Vector3D>();
                for (var j:int = 0; j < 10; j++) {
                    vertices[i][j] = new Vector3D(uRand(), uRand());
                    trace(i, j);
                    if(i>0 && j>0)
                        noise50(bd, i*50,j*50,vertices[i-1][j-1], vertices[i][j-1], vertices[i-1][j], vertices[i][j]);
                }
            }
               

           
           
       
        }
       
        private function uRand():Number
        {
            return Math.random()*2-1;
        }
       
        private function noise50(bd:BitmapData, destX:int, destY:int, gx0y0:Vector3D, gx1y0:Vector3D, gx0y1:Vector3D, gx1y1:Vector3D):void
        {
            var x0:Number = 0;
            var y0:Number = 0;
            var x1:Number = 1;
            var y1:Number = 1;   

           
            for (var yi:Number = 0.00; yi < 1; yi+=0.02) {
                for (var xi:Number = 0.00; xi < 1; xi+=0.02) {
                    var s:Number = gx0y0.dotProduct(new Vector3D(xi-x0, yi-y0));
                    var t:Number = gx1y0.dotProduct(new Vector3D(xi-x1, yi-y0));
                    var u:Number = gx0y1.dotProduct(new Vector3D(xi-x0, yi-y1));
                    var v:Number = gx1y1.dotProduct(new Vector3D(xi-x1, yi-y1));
                   
                    var sxi:Number = 3*(xi-x0)*(xi-x0) - 2*(xi-x0)*(xi-x0)*(xi-x0);
                    var syi:Number = 3*(yi-y0)*(yi-y0) - 2*(yi-y0)*(yi-y0)*(yi-y0);                   
                    var a:Number = s+sxi*(t-s);
                    var b:Number = u+sxi*(v-u);                   
                    var zi:Number = a+syi*(b-a);
                   
                    bd.fillRect(new Rectangle(destX+xi*50,destY+yi*50,1,1),0x010203*int((zi+0.5)*4095));
                }
            }
        }
       
    }
   
}


SWF파일과 동영상파일 각각 첨부.









영화 '겨울왕국(Frozen, 2013)'의 한 장면으로 나오는 시계를 플래시로 만들어서 HTML5로 변환.

크롬, 파이어폭스, 최신버전의 익스플로러(익스10 이상)로 봐야 제대로 나옵니다.
(한스머리를 누르면 숨어있는 초침을 볼 수 있습니다.. 다시 누르면 사라져요
그냥 디버깅용 초침이라서 깊이처리는 안했습니다)

현재 시간이 나옵니다









▼이곳에 플래시가 삽입되어 있습니다. 




1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
package kr.tibyte
{
    import flash.display.Bitmap;
    import flash.display.BitmapData;
    import flash.display.Shape;
    import flash.display.Sprite;
    import flash.events.Event;
    import flash.events.MouseEvent;
    import flash.geom.Point;
    import flash.geom.Vector3D;
     
    /**
     * ...
     * @author
     */
    public class Main extends Sprite
    {
         
        [Embed(source="../../sample1.png")]
        private var SampleImage1:Class;
        [Embed(source="../../sample2.png")]
        private var SampleImage2:Class;
         
        private var _bitmaps:Vector.<Bitmap> = new Vector.<Bitmap>(IMG_NUM);
        private var _imgArr:Vector.<Sprite> = new Vector.<Sprite>(IMG_NUM);
        private var _imgWidth:int = 120;
        private var _imgHeight:int = 80;
        private var _r:Number; //회전반경
        private var _yaw:Number = 0;
        private var _container:Sprite = new Sprite();
         
        private const IMG_NUM:int = 6;
        private const THETA:Number = 0.003*3/180*Math.PI; //회전각속도
        private const MARGIN:int = 20; //이미지 간격
         
        public function Main():void
        {
             
            for (var i:int = 0; i<IMG_NUM; i++)
            {
                if (Math.random()>0.6)
                    _bitmaps[i] = new SampleImage1();
                else
                    _bitmaps[i] = new SampleImage2();
                 
                _bitmaps[i].x = -_bitmaps[i].width/2-MARGIN;
                _bitmaps[i].y = -_bitmaps[i].height/2;
                _imgArr[i] = new Sprite();
                _imgArr[i].addChild(_bitmaps[i]);
                _imgArr[i].width = _imgWidth;
                _imgArr[i].height = _imgHeight;
                _container.addChild(_imgArr[i]);
            }
            //회전반경을 이미지크기+마진값에 딱 맞게 설정
            _r = (_imgWidth+2*MARGIN)/(2*Math.tan(Math.PI/IMG_NUM));
             
            _container.x = 200;
            _container.y = 150;
            this.transform.perspectiveProjection.projectionCenter = new Point(_container.x, _container.y);
            addChild(_container);
             
            stage.addEventListener(Event.ENTER_FRAME, enterFrameHandler);
            stage.addEventListener(MouseEvent.MOUSE_MOVE, mouseMoveHandler);
        }
         
        private function mouseMoveHandler($evt:MouseEvent):void
        {
             
            var old:Point = this.transform.perspectiveProjection.projectionCenter;
            old.y = stage.mouseY;
            root.transform.perspectiveProjection.projectionCenter = old;
         
        }
         
        private function enterFrameHandler($evt:Event):void
        {
             
            //마우스로 회전제어
            _yaw += THETA*(stage.mouseX-stage.stageWidth/2);
             
            display();
         
        }
         
 
         
        private function display():void
        {
            var angle:Number;
            for (var i:int = 0; i<IMG_NUM; i++)
            {
                angle = _yaw+i*2*Math.PI/IMG_NUM;
                _imgArr[i].x = _r*Math.cos(angle);
                _imgArr[i].z = _r*Math.sin(angle);
                 
                //angle과 수직이 되도록 rotationY 를 설정
                _imgArr[i].rotationY = (180/Math.PI)*-1*(Math.PI/2+angle);
                 
                 
                /* //rotationY 대신 transform속성으로 회전하기
                   _imgArr[i].transform.matrix3D.pointAt(new Vector3D(),Vector3D.Z_AXIS, new Vector3D(0, -1, 0));
                 */
            }
             
            //다시 그리기
            var seq:Vector.<int> = genSequence(IMG_NUM);
            seq.sort(compare);
             
            _container.removeChildren();
            for (i = 0; i<IMG_NUM; i++)
            {
                _container.addChild(_imgArr[seq[i]]);
            }
         
             
            //z소팅을 위한 비교함수
            function compare($a:int, $b:int):Number
            {
                if (_imgArr[$a].z>_imgArr[$b].z)
                    return -1;
                else if (_imgArr[$a].z==_imgArr[$b].z)
                    return 0;
                else
                    return 1;
            }
        }
 
         
        private function genSequence($n:int):Vector.<int>
        {
            var arr:Vector.<int> = new Vector.<int>($n);
            for (var i:int = 0; i<$n; i++) {
                arr[i] = i;
            }
            return arr.concat();
        }
    }
}




견본용 작품

(▼여기에 플래시가 첨부되어 있습니다)

화면을 클릭하면 탱크가 놓여집니다.

탱크 이미지 : fortress 2 blue













액션스크립트3.0으로 만든 RGB큐브.



(▼여기에 플래시가 삽입되어 있습니다)




1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
import flash.display.Shape;
import flash.geom.Vector3D;
import flash.geom.Matrix3D;
import flash.events.MouseEvent;
 
var scale:int = 160;
var density:int = 10;
var densityCube:int = density*density*density;
var points:Vector.<Shape> = new Vector.<Shape>(densityCube);
var pointsPosition:Vector.<Vector3D> = new Vector.<Vector3D>(densityCube);
var centralPoint:Vector3D = new Vector3D(stage.stageWidth/2, stage.stageHeight/2, scale/2);
var angleSpd:Number = 0;
var mouseAngle:Number = 0;
var mouseDistance:Number = 0;
var mouseSin:Number = 0;
var mouseCos:Number = 1;
 
for(var i_z:int=0; i_z<density; i_z++) {
    for(var i_y:int=0; i_y<density; i_y++) {
        for(var i_x:int=0; i_x<density; i_x++) {
            var index:int = density*density*i_z+density*i_y+i_x;
            var color:uint = int(i_z/density*256)<<16|int(i_y/density*256)<<8|int(i_x/density*256);
            points[index] = new Shape();
            points[index].graphics.beginFill(color);
            points[index].graphics.drawRect(0,0,4,4);
            points[index].graphics.endFill();
             
            pointsPosition[index] = new Vector3D();
            pointsPosition[index].x = centralPoint.x-scale/2 + i_x*scale/(density-1);
            pointsPosition[index].y = centralPoint.y-scale/2 + i_y*scale/(density-1);
            pointsPosition[index].z = centralPoint.z-scale/2 + i_z*scale/(density-1);
             
            points[index].x = pointsPosition[index].x;
            points[index].y = pointsPosition[index].y;
            points[index].z = pointsPosition[index].z;
            addChild(points[index]);
        }
    }
}
 
 
stage.addEventListener(Event.ENTER_FRAME, enterFrameHandler);
function enterFrameHandler(evt:Event):void
{
    for(var index:int=0; index<densityCube; index++) {
        pointsPosition[index].x -= centralPoint.x;
    &nb