[Broadcast Video Streaming]

 

 

 

640 * 480 * 4 만큼의 컬러 바이트 배열을 실시간으로 각 SWF 로 전송하여 그 컬러 배열 대로 bitmap을 만들어 실시간으로 업데이트 했다.

초당 1.2 M 전송율 , 로컬 네트워크로 묶을 경우 대역폭을 생각해서 공유기를 선택하면 효율적일듯 함.

 

문제

화면 깜빡거림 문제 : 82 바이트 만큼의 크기가 맞지 않는다.

화면 색 : 전송되는 컬러 바이트 배열순서와 복원 되는 컬러 바이트 배열 순서가 서로 틀려서 나온 결과

ARGB , BGRA , RGBA

 

 

결과 ㅡ

돈주고 화면 스트림 장비나 , 서버를 산다던데,,, 구지,,,

 

 

 

'C#' 카테고리의 다른 글

sqlMetal 사용법  (10) 2013.01.11
Activator 를 이용한 Type Instance 생성  (32) 2012.12.29
[Broadcast Video Streaming]  (149) 2012.11.27
[Tcp] 연속적인 정보를 송출시 유의점  (91) 2012.11.04
[MEMO]  (58) 2012.10.14
[WCF] 간단한 채팅 샘플  (61) 2012.05.12
Yamecoder 야매코더_
C# 2012.11.27 19:05

[AS3 Worker] Thread Test

 

드디어 As3 에 Worker 라는것이 생겼다.

바로 Thread 이다.

하지만 , 방법이 조금 지저분 하다.

실행되고 있는 바이트 코드를 그대로 복제하여 ,백그라운드에서 실행하고 그 결과를 메시지 체널 형태로 주고 받는다.

정확한 Thread 의 개념 보다는 .NET 의 BackgroundWorker 쯤으로 생각하면 될듯하고

쓰레드를 직접실행할 클래스 형태가 필요하다.

 

아래의 ThreadManager 는 구차한 Worker 생성과정을 미리 생성하고 Thread 객체를 관리하는 매니저 역할이다.

또하나의 Worker1 클래스는 쓰레드 개체가 생성하게될 , 즉 쓰레드가 수행할 내용이다.

아래의 실험은 같은 개체를 동시에 실행 하였을때 쓰레드 블럭킹이 발생하는지 실험하는 코드이다.

 

* ThreadManager

 
package
{
    import flash.display.Sprite;
    import flash.events.Event;
    import flash.events.KeyboardEvent;
    import flash.ui.Keyboard;
    
    import jjongun.threadWorker.Thread;
    import jjongun.threadWorker.ThreadEvent;
    import jjongun.threadWorker.ThreadManager;
    
    public class TestThread3 extends Sprite
    {
        private var thread1 : Thread;
        private var thread2 : Thread;
        public function TestThread3()
        {
            ThreadManager.Init(this.stage);
            
            thread1 = ThreadManager.getInst().createThread(Work1);
            thread2 = ThreadManager.getInst().createThread(Work1);
            
            thread1.addEventListener(ThreadEvent.RECEIVE , receive);
            thread2.addEventListener(ThreadEvent.RECEIVE , receive);
            
            thread1.start();
            thread2.start();
            
            stage.addEventListener(KeyboardEvent.KEY_UP , stageKup);
        }
        
        protected function stageKup(e:KeyboardEvent):void
        {
            if(e.keyCode == Keyboard.A)
            {
                trace("A");
                thread1.send(Work1.F1);
            }
            else if(e.keyCode == Keyboard.S)
            {
                trace("S");
                thread2.send(Work1.F2);
            }
        }
        
        protected function receive(e:ThreadEvent):void
        {
            if(e.currentTarget == thread1)
            {
                trace(e.receiveData);
            }
            else if(e.currentTarget == thread2)
            {
                trace(e.receiveData);
            }
        }
    }
}

 

 

 

 

package
{
    import flash.utils.getTimer;
    
    import jjongun.threadWorker.AbsThreadWorker;
    
    public class Work1 extends AbsThreadWorker
    {
        public function Work1()
        {
            super();
        }
        
        public static const F1 : String = "F1";
        public static const F2 : String = "F2";
        protected override function threadMessage(command:*):void
        {
            trace("command " , command);
            if(command == F1)
            {
                f1();
            }
            else if(command == F2)
            {
                f2();
            }
        }
        
    
        
        private function f1():void
        {
            trace("start _ f1 " , getTimer());
            
            var b : Boolean = true;
            var cur : Number = getTimer();
            while(b)
            {
                if(getTimer() - cur > 3000)
                {
                    b = false;
                }
            }
            
            trace("end _ f1" , getTimer());
        }
        
        private function f2():void
        {
            trace("start _ f2 " , getTimer());
            
            var b : Boolean = true;
            var cur : Number = getTimer();
            while(b)
            {
                if(getTimer() - cur > 3000)
                {
                    b = false;
                }
            }
            
            trace("end _ f2" , getTimer());
        }
    }
}

 

결과 블럭킹이 전혀 발생하지 않았고 상상했던 Thread의 역할을 충분히 수행해 주었다.

 

주의할점은 현재 시점으로 11.4 버전 -swf-version=17 만 가능하다.

혹 그 윗버전의 SDK 로 시도 해보았지만 작동이 안된다. 이유는 모른다. 버그 같다. 어도비 포럼에도 질문만 있을뿐 답이 없다.

머 ,, 곧 해결 되겠지만 , 현재 11.4 버전 만 된다. 버전 체크를 하여 수행하여야 하겠다.

 

'AS3' 카테고리의 다른 글

FLA Auto build utility for flashbuilder developer  (2) 2014.02.22
[AS3] asmx 사용하기  (87) 2013.01.12
[AS3 Worker] Thread Test  (2920) 2012.11.15
간단한 AS3 바이트 버퍼 나누기  (110) 2012.03.09
[Multitouch on 3D World]  (92) 2012.01.17
[Base64]  (282) 2011.12.19
Yamecoder 야매코더_
tags : AS3, Thread, worker
AS3 2012.11.15 23:38

[Base64]




6메가 픽셀 정도의 비트맵 데이터를 JPEG 로 인코딩 하고 Base64로 변환해 보았다.
 
package
{
    import by.blooddy.crypto.Base64;
    import by.blooddy.crypto.image.JPEGEncoder;
    
    import flash.display.Bitmap;
    import flash.display.Loader;
    import flash.display.Sprite;
    import flash.events.Event;
    import flash.filesystem.FileStream;
    import flash.net.URLRequest;
    import flash.utils.ByteArray;
    import flash.utils.getTimer;
    import flash.utils.setTimeout;
    
    import jjongun.devUtil.Stats;
    
    
    [SWF(frameRate="60")]
    public class Base64_1 extends Sprite
    {
        public function Base64_1()
        {
            this.stage.addChild( new Stats);
            
            var loader : Loader = new Loader();
            loader.load( new URLRequest("sample_6MP_Image.jpg"));
            loader.contentLoaderInfo.addEventListener(Event.COMPLETE , complete);
        }
        
        protected function complete(e:Event):void
        {
            var bitmap : Bitmap = e.currentTarget.content as Bitmap;
            
            var time : Number = getTimer();
            var imgBytes : ByteArray = JPEGEncoder.encode(bitmap.bitmapData , 100);
            trace( "JPEGEncode : " , getTimer() - time );
            
            time = getTimer();
            var str : String = Base64.encode(imgBytes , true);
            trace( "Base64Encode : " , getTimer() - time );
            
            
            
        }
    }
}

결과는
JPEGEncode :  1498
Base64Encode :  54

i7에서 54ms 정도로 쓸만하다

종전의 C# 소켓과 통신을 위해 헤더버퍼를 잡고 뒤에 데이터를 보냈는데 그럴 필요 없이
xml 에 Base64를 묶어서 보내는 프로토콜을 이용하면 좀더 편리하고 안전한 통신이 보장된다.

아울러 WCF 서버와 자료 교환에도 용이 할듯 하다.


Yamecoder 야매코더_
tags : AS3, base64
AS3 2011.12.19 10:30

[AS3 , Enum] AS3 에서 Enum Type 을 구현하자 (Fake Enum in AS3)


C#과 AS3 를 혼용 하여 사용하는 본인에게 AS3 에서 가장 아쉬운것중 하나는 Enum 타입이 없다는것이다.
물론 

class SomeClass{  
    static const ENUMStr : String = "ENUM_STRING";
}
이런식으로 클래스 안에서 열거 하여 사용은 가능하다. 그러나 관리 적인 측면에서 아래와 같은 경우가 발생할때 참으로 애매하다.

function insertEnumValue (_enumType : String):void
{
if(_enumType == SomeClass.ENUMStr ){ ... }
}


 위와 같은 상황에서 _enumType:String 의 값을 넣는 과정에서 함수 안의 코드가 SomeClass 에서 정확히 정의된 스트링을 받아 처리 한다면 아무런 문제가 없다. 하지만 함수의 인자 타입이 String 이다. 이것의 의미는 구지 함수 인자를 SomeClass.ENUMStr 을 안넣어도 아무런 문제가 되지 않는다 (쇠고랑 안찹니다... 경찰이 안잡아가요...)
컴파일러는 단지 일치하는 String 이 없을 뿐 , 에러를 뱉지 않지만 , 그게 더 문제다. 제3자가 이 함수를 사용한다고 하자 , 혹은 오래전에 작성했던 코드를 본인이 본다고 해보자. 아마 작성자가 SomeClass.ENUMStr 을 넣어 주리라고 기대하는것은 너무 아름다운 순정만화 같은 생각 아닌가?
(물론 본인은 예전에 함수 위에 주석으로 설명을 적어 올바른 작성을 유도 하였다. 하지만 코드 자체가 오염될 여지가 있고 제 3자 가 또 다른사람에게 코드를 넘길때 , 주석이 온전히 존재하고 있을까?)

여차 하면 오리무중이 될수 있다.

또 한가지 문제 상황이 생긴다. 바로 Event 타입 상수 이다. 보통 이벤트를 이렇게 작성한다.
class SomeEvent :Event
{
    public static const EventType : String = "SomeEvent.EventType"
    public SomeEvent (type:String, ..(생략)..){...}
}

와 같이 작성하고 ,

dispatchEvent( new SomeEvent( SomeEvent.EventType ));

처럼 이벤트를 발생시킨다.

만약 SomeEvent 에 종전과 같은 방식으로 ENUMStr 를 작성 한다고 생각해보자.

class SomeEvent :Event
{
    static const ENUMStr : String = "ENUM_STRING";
    public static const EventType : String = "SomeEvent.EventType"   
    public SomeEvent (type:String, ..(생략)..){...}
}

그리고 이벤트를 발생(dispatchEvent) 시키고 받을때(addEventListener)를 생각해 보면
아마 혼동이 팍! 올것이다.

dispatchEvent( new SomeEvent( SomeEvent.ENUMStr )); //??
dispatchEvent( new SomeEvent( SomeEvent.EventType)); //??


addEventListener(SomeEvent.ENUMStr , func ) //??
addEventListener(SomeEvent.EventType, func ) //??



참.. 생각하기도 싫은 상황이다. 이것을 위해 이벤트의 코드 힌트를 보고 인간적으로 이해를 해야 하는가?
예를 들어 "EventType 이라고 적어 놓았으니 , Event 상수겠지..." 이런 생각은 물론 거의 대부분 맞다. 하지만
어디까지나 예상일뿐 명확하지는 않다.


그래서 이러한 상황을 타계 하고자 다른 언어에서 존재하는 가벼운 Enum 타입이 필요 하다.


원문 : http://scottbilas.com/blog/faking-enums-in-as3/
 
package jjongun.devUtil.enum
{
    import flash.utils.describeType;

    public class EnumUtil
    {
        public static function InitEnumConstants(inType : *):void
        {
            var type : XML = describeType(inType);
            
            for each(var constant : XML in type.constant)
            {
                inType[constant.@name].text = constant.@name;
            }
        }
    }
}


추상 클래스가 필요하다.
 
package jjongun.devUtil.enum
{
    public class AbsEnum
    {
        public var text :String;
        public function AbsEnum(ChildClass :Class)
        {
            EnumUtil.InitEnumConstants(ChildClass);
        }
    }
}



실제 ENUM을 구현하는 클래스 이다. 여기서 바로 ENUM을 선언하여 사용한다.
 
package
{
    import jjongun.devUtil.enum.AbsEnum;

    public class EnumTEST extends AbsEnum
    {
        public static const INIT : EnumTEST = new EnumTEST();
        public static const ENUMTEST : EnumTEST = new EnumTEST();
        
        public function EnumTEST()
        {
            super(EnumTEST);
        }
    }
}


실제 사용이다. 따로 new 키워드를 사용할 필요 없이 여느 enum 과 같은 형태로 사용이 가능하다.
 
        public function TESTCLASS()
        {
                        
            testEnum(EnumTEST.ENUMTEST);
        }
        public function testEnum(type :EnumTEST):void
        {
            if(type == EnumTEST.ENUMTEST)
            {
                trace("ok!" , type);
            }
        }


Yamecoder 야매코더_
AS3 2011.10.15 23:37

[TwitPic 모듈] 트윗픽을 손쉽게 활용하자





사용법

소켓 IP : 로컬 (127.0.0.1)
소켓 포트 : 55667

명령전송 (헤더) : 256 바이트 헤더에

  "$ID:"+$id+"$PW:"+$pw+"$USERID:"+$userId+"$TEXT:"+$text; 

나머지 남는 바이트는 공백 " " 처리 를 하여 256 바이트를 채운후 256바이트 이후 JPG , PNG 포멧을 싣어 보낸다

제약사항 : 이미지파일이 4MB를 넘지 않을것, 같은 아이피로 시간당 500번 이상 포스팅 금지

* TEST Flash App 버튼 클릭시 테스트용 플래시 어플이 실행됨



Flash AS3 용 라이브러리 


활용법
 
var target : FileReference = event.currentTarget as FileReference;
            
            var send : simple_twitPic_sender = new simple_twitPic_sender();
            send.sendMsg(
                idTx.text, //id
                pwTx.text, //pw
                userTx.text, //userid
                text.text,//text
                target.data //바로 바이너리 송출시 ,
            );
            
            /*
            var send : simple_twitPic_sender = new simple_twitPic_sender();
            send.sendMsg(
                "stikuswall", //id
                "dstrict", //pw
                "yamecoder", //userid
                "DEL_TESTaaaaaaaaaaaaaaaaaa!",//text
                send.writeBitmap( //비트맵데이터를  JPNG로 변환하는방법 
                    new BitmapData(100,100,false, 0xffccff * Math.random()*100) //bitmapData
                )
            );*/


다운로드 :

Yamecoder 야매코더_
C# 2011.06.09 11:27

[Molehill + AWAY3D] Hello Cube!


드디어 ! Molehill을 돌려봤다 생각보다 간단했다.

물론 Flash Builder 최신버전인 Burrito 에 서 테스트를 하였다 .

바로가기

튜토리얼을 돌리기 위해 몇가지가 필요한데

1.
우선 정식버전이 나오기 전까지 FlashPlayer11 인큐베이터 버전을 사용하자
http://labs.adobe.com/downloads/flashplatformruntimes_incubator.html


2.
flex4.5 Hero Sdk 가 필요하다.
http://opensource.adobe.com/wiki/display/flexsdk/Download+Flex+Hero
아래의 표시대로 4.5.19786 버전이 필요하다.


3.Syntex를 잡기위한 새로운 swc
http://download.macromedia.com/pub/labs/flashplatformruntimes/incubator/flashplayer_inc_playerglobal_022711.swc



4. Away3d 패치




위의 파일들을 죄다 모아 놓고 조립을 하면된다.

조립은 아래의 그림에 설명되어 있다.


기본적인 4.5.19786 버전을 토대로 해당 경로에 파일들을 복사하여 넣거나 덮어 쓴다.
away3d 패치는 압축을 풀어 sdk 최상단 폴더에 덮는다.



완료가 되었다면 이제 Molehill sdk 가 완성되었다!


그렇타면 플래시 빌더에서 sdk 를 잡고 간단한 코딩을 해보자!


코드는 사실 볼것도 없이 간단 명료하다.

 
package
{
    import away3d.containers.View3D;
    import away3d.materials.ColorMaterial;
    import away3d.primitives.Cube;
    
    import flash.display.Sprite;
    import flash.events.Event;
    
    public class testMH extends Sprite
    {
        private var view : View3D
        private var cube : Cube;
        
        public function testMH()
        {
            view = new View3D();
            addChild(view);
            var matt : ColorMaterial = new ColorMaterial(0xcc );
            cube = new Cube(matt);
            view.scene.addChild(cube);
            addEventListener(Event.ENTER_FRAME , en);
        }
        
        protected function en(event:Event):void
        {
            cube.rotationY += 10;
            view.render();
        }
    }
}


아직 exe 플레이어가 나오기 전이기 때문에 브라우져 상에서 디버깅을 해야 한다.
결과는 아래처럼 나온다면 성공이다.

이제 쫌 본격적으로 GPU를 물려 볼때가 왔다.( XNA 는 어쩔까 = = ;;;; )



Yamecoder 야매코더_
AS3 2011.03.31 14:12

[SimpleFileWriter] AS3 에서 파일을 저장하자



기존 의 http://www.scripter.co.kr/entry/Simple-Text-Writer-V01-간편한-파일-쓰기-어플 를 업그래이드 해봤다.

예전에는 Text 만 되는 반면 이번꺼는 모든 As3 의 ByteArray를 죄다 기록할수 있다.

사용법

as3

 
package 
{
    import flash.display.BitmapData;
    import flash.utils.ByteArray;
    import jjongun.server.file_Socket_Server;
    import flash.display.Sprite;

    public class Main extends Sprite
    {
        public function Main()
        {
            var sp : Sprite = new Sprite();
            sp.graphics.beginFill(0xcc);
            sp.graphics.drawCircle(0, 0, 100);
            addChild(sp);
            
            //test
            var writer : file_Socket_Server = file_Socket_Server.getInstance();
            
            var data : BitmapData = new BitmapData(400, 400);
            data.draw(this);
            writer.writeFile("e:\test3.Png", writer.writeBitmap(data));
            
            
            var d : ByteArray = new ByteArray();
            d.writeUTFBytes("WOW!");
            writer.writeFile("e:/WOW.txt", d);
            
            
            var xml : XML = <root>AAA</root>;
            writer.writeFile("e:/test.xml", writer.writeText(xml.toXMLString()));
        }
    }
}

주의점은 경로를 적을때 "\" 를 적으면 에러난다.

관련 클래스는 첨부파일을 아래 "get AS3 file "에서 얻을수 있다.




* 버그수정 : 오버라이트시 파일바이트를 완전이 최신화 하지 못하는 버그가 있었다.
Yamecoder 야매코더_
C# 2011.03.10 14:37

[FlashPlayer11 ] Molehill




우선 ..
http://labs.adobe.com/downloads/flashplatformruntimes_incubator.html
로 가서
Download active-x for Windows — for Internet Explorer only (EXE, 3.5 MB)
를 설치한다 .


나중에 언인스톨은
  1. Download the Flash Player Incubator uninstaller for Windows


로 한다..
그다음 ..

http://www.ringo.nl/projects/away3d/broomstick/LoaderOBJTest.html
http://infiniteturtles.co.uk/projects/away3d/broomstick/ShallowWaterDemo.html
기타 등등..

http://www.away3d.com/
에 가면 데모들이 있다..

http://blog.theflashblog.com/?p=2607
여긴 더 많다 .

플래시에도 GPU의 시대가 왔다.


Yamecoder 야매코더_
AS3 2011.03.09 11:45

Socket 에 Header 정보와 같이 묶어 보내기



정보를 보낼때 헤더는 참 유용하고 필수적이다. 편지를 쓴다고 생각하자면, 받는사람 , 주소 , 우편번호 등등이 헤더에 
해당할것이고 , 동내 구멍가게에서 라면을 사더라도 , 이라면이 무슨라면인지 , 매운맛인지 순한맛인지 ,조리법은 어떻
게 되는지 등등이 해더에 해당하는 정보라고 생각한다.

이처럼 무언가를 보낼때 이것이 어떠한 것이다 라는것을 표현할때는 조금은 바이트 배열을 이해할 필요가 있다.
as3 에서는 ByteArray에 해당할것이고 , c# 에서는 Stream 등에 해당할것이다.

그리고 해더는 Text로 읽을수 있는 정보일것이고, (물론 어느 오브젝트 바이트 배열로 하겠다면 구지 텍스트가 아니어도 된다. ) 컨텐츠 영역은 Text일수도 있고 바이너리 일수도 있다. 

문제는 없다. 뭐 어찌되었든 바이트로 넘어오고 약속된 영역을 텍스트로 치환하느냐, 바이너리로 통과 시키냐의 차이이다. 

아래의 그림은 헤더를 보내는 한가지 아이디어가 될것이다. 무조건 0바이트 부터 128 바이트까지 텍스트로 된 헤더라고 가정하고 있다. 혹 헤더가 128이 채워지지 않았다면 인위적으로 채워 버려 꼭 128을 만들어 버린다. ( 내가 생각하는 헤더에는 경로 , 타입, 기타코멘트 등등해서 128바이트면 충분하다고 생각해서 128이라고 한것, 그뿐이다.)

그리고 129번째 바이트 부터는 원하는 내용을 채우면 된다.
(이러한 해더의 아이디어를 발전시키고 싶다면 유명한 포토샵파일 PSD 의 바이트코드를 분석해 보라. 기가막히게 순수하고 심플하게 되어 있다.)



그럼 위의 그림을 토대로 코드를 한번 보자 

As3 에서 헤더 정보로 경로를 Text형대로 보내고 나머지는 카메라에서 캡쳐 받은 png포멧을 보낸다.
c#은 헤더로 넘어온 것을 FileStream의 경로로 지정하고 내용을 해당 경로에 저장한다.(버퍼의 사용은 이전글을 참고)

c# 서버
using System;
using System.Windows;
using System.Net.Sockets;
using System.Threading.Tasks;
using System.IO;
using System.Net;
using System.Text;

namespace testEncoderRecieve
{
    public partial class MainWindow : Window
    {
        public MainWindow()
        {
            InitializeComponent();
            this.Loaded += new RoutedEventHandler(MainWindow_Loaded);
        }

        private Task ServerThread;
        private TcpListener server;
        void MainWindow_Loaded(object sender, RoutedEventArgs e)
        {
            ServerThread = new Task(startServerThreaed);
            server = new TcpListener(System.Net.IPAddress.Parse("127.0.0.1"),5555);
            //
            ServerThread.Start();
        }
        void startServerThreaed()
        {
            //서버 스레드가 시작되고 서버가 시작되었다.
            Console.WriteLine("startServerThread");
            server.Start();

            //컨텐츠 버퍼와 헤더버퍼를 생성하였다.
            Byte[] buffer = new Byte[64];
            Byte[] headerBuffer = new Byte[128];
            int testCount = 0;
            while (true)
            {
                TcpClient client = server.AcceptTcpClient();
                NetworkStream netStream = client.GetStream();
                //netStream 에서 지정된 해더 바이트버퍼 만큼읽어서
                //해더정보를 입수한다.
                //그리고 netStream의 포지션은 128 이 되었다.
                netStream.Read(headerBuffer, 0, headerBuffer.Length);
                String rowHeader = Encoding.ASCII.GetString(headerBuffer);

                //String.Trim 을 이용해 불필요한 공백을 
                //제거하고 딱 필요한 헤더만 추출했다.
                string header = rowHeader.Trim();
                FileInfo fInfo = new FileInfo(header);

                //이전과 같이 파일 스트림을 생성하였고,
                //파일경로로는 헤더에서 넘어온 정보를 사용하였다.
                //그리고 여기서 읽을 netStream의 포지션은 129부터 이다.
                FileStream fs = new FileStream(fInfo.FullName, FileMode.OpenOrCreate, FileAccess.Write);
                int i = 0;
                while ((i = netStream.Read(buffer, 0, buffer.Length)) > 0)
                {
                    fs.Write(buffer, 0, i);
                }
                fs.Close();
                netStream.Close();
                client.Close();
                ++testCount;
            }
        }
    }
}


as3 클라이언트
package {
    import flash.events.Event;
    import flash.net.Socket;
    import flash.utils.ByteArray;
    import flash.display.Bitmap;
    import flash.display.BitmapData;
    import flash.display.Sprite;
    import flash.events.MouseEvent;
    import flash.media.Camera;
    import flash.media.Video;
    /**
     * @author superSc_PC
     */
     
    [SWF(width = "1000")]
    public class Main extends Sprite
    {
        private var cam : Camera;
        private var vid : Video;
        private var captureBitmap : Bitmap;
        
        private var socket : Socket;
        private var headerBufferSize : int = 128;
        private var header : ByteArray = new ByteArray();
        private var captureByte : ByteArray;
        public function Main()
        {
            //필요한것들을 생성했다.
            cam = Camera.getCamera();
            vid = new Video();
            vid.attachCamera(cam);
            captureBitmap = new Bitmap(new BitmapData(vid.width, vid.height));
            captureBitmap.x = vid.width;
            addChild(vid);
            addChild(captureBitmap);
            stage.addEventListener(MouseEvent.CLICK    , takePic);
            
            socket = new Socket();
            socket.addEventListener(Event.CONNECT, connectFn);
            
            //header 에 필요한정보를 입력하였다.
            //그리고 바이트의 공백을 매꾸기 위해 while루프로 쓰레기 정보들을
            //입력하였고 마지막 바이트로 줄바꿈"\n"을 입력 하였다.
            header.writeUTFBytes("d:/testAS.png");
            while(header.position < headerBufferSize-1)
            {
                header.writeUTFBytes(" ");
            }
            header.writeUTFBytes("\n");
        }
        
        
        private function connectFn(event : Event) : void {
            if (captureByte != null && captureByte.length > 0)
            {
                //이전과 다르게 소켓에 연달아 2개의 바이트들을 보낸다.
                //처음에는 헤더정보를 다음엔 캡쳐된 png를 보낸다.
                //역시나 보내고 난뒤에 소켓을 죽인다.
                socket.writeBytes(header);
                socket.writeBytes(captureByte);
                socket.flush();
                socket.close();
            }
        }

        private function takePic(event : MouseEvent) : void {
            captureBitmap.bitmapData.draw(vid);
            captureByte = PngEncoder.encode(captureBitmap.bitmapData);
            captureByte.position = 0;
            if(socket.connected == false)
            {
                socket.connect("localhost", 5555);
            }
        }
    }
}


Yamecoder 야매코더_
C# 2011.03.04 23:35

[TCPSocket] 안전한 Socket 연결과 버퍼데이터를 설정한 데이터전송 (C# <-> As3)


소켓사용을 꺼려하는 이유중 하나는 연결의 지속성을 보장하기가 까다롭기 때문이다. 또한 그것을 서로 스로스 체킹

하는 코드를 작성하기가 번거럽기 때문이기도 하다.

하지만 생각을 바꾸어 왜? 소켓을 항상 연결시켜 놔야 할까? 물론 실시간 데이터전송 같은경우 , 즉 마우스 좌표에 따라 무었을 지속적으로 움직여야 한다거나 하는 실시간적인 반응이 필요한 경우로 생각할수 있겠다.

하지만 데이터의 전송, 어느 순간 상태의 알림 등등의 경우에는 연결을 지속적으로 유지해야 할 필요가 없다.
본 모델은 이미 

에서 사용하였고 지금까지 별 탈없이 사용한 모델을, UTF텍스트가 아닌 바이너리를  전송하는 경우로 생각하여 바꾸어 보았다.

목표는 
1) 예전에 철없던 시절의 소켓서버 ( http://www.scripter.co.kr/entry/socket-c-server-as3-client )의 비효율성을 타파하여 좀더 세련된 방법으로 소켓을 구성하는 법.

2) "1)"의 연속적인 개념으로, 지속적인 연결이 아닌 한방에 한번씩 연결하여 전송하고 연결을 종료하는 방법.

3)큰 파일을 무리없이 전송하기 위해 버퍼를 설정하여 끊어 읽어 기록하는 방법

을 정리해보겠다.


우선 간단한 순서도를 보면 이러하다.


c# 서버
using System;
using System.Windows;
using System.Net.Sockets;
using System.Threading.Tasks;
using System.IO;

namespace testEncoderRecieve
{
    public partial class MainWindow : Window
    {
        public MainWindow()
        {
            InitializeComponent();
            this.Loaded += new RoutedEventHandler(MainWindow_Loaded);
        }

        private Task ServerThread;
        private TcpListener server;
        void MainWindow_Loaded(object sender, RoutedEventArgs e)
        {
            ServerThread = new Task(startServerThreaed);
            server = new TcpListener(System.Net.IPAddress.Parse("127.0.0.1"),5555);
            //TcpListener를 생성하고, 서버 스레드가 시작되었다
            ServerThread.Start();
        }
        void startServerThreaed()
        {
            //서버를 시작시킨다.
            server.Start();

            //버퍼를 설정한다. 우선64바이트 만큼만...
            Byte[] buffer = new Byte[64];

            int testCount = 0;
            while (true)
            {
                //클라이언트를 대기한다. 클라이언트로 부터 접속신호가 있기 전까지 루프는 여기서 멈춤.
                TcpClient client = server.AcceptTcpClient();
                //클라이언트가 접속하고 스트림을 가져 온다.
                NetworkStream netStream = client.GetStream();
                //파일스트림을 생성하여 FileAccess.write로 한다.
                FileStream fs = new FileStream(@"d:\test" + testCount + ".png", FileMode.OpenOrCreate , FileAccess.Write);
                int i = 0;
                while ((i = netStream.Read(buffer, 0, buffer.Length)) > 0)
                {
                    //여기서 정수i가 0보다 클때까지, 즉 끝까지 루프를 반복하며 정해진 버퍼만큼 기록한다.
                    fs.Write(buffer, 0, i);
                }
                //루프가 끝나면 모든 스트림을 종료하고 다시 대기상태로 돌아간다.
fs.Close(); netStream.Close(); client.Close(); ++testCount; } } } }



as3 클라이언트
package {
    import flash.events.Event;
    import flash.net.Socket;
    import flash.utils.ByteArray;
    import flash.display.Bitmap;
    import flash.display.BitmapData;
    import flash.display.Sprite;
    import flash.events.MouseEvent;
    import flash.media.Camera;
    import flash.media.Video;
    /**
     * @author superSc_PC
     */
     
    [SWF(width = "1000")]
    public class Main extends Sprite
    {
        private var cam : Camera;
        private var vid : Video;
        private var captureBitmap : Bitmap;
        
        private var socket : Socket;
        public function Main()
        {
            //필요한것들을 생성하며 캡쳐환경을 만든다.
            cam = Camera.getCamera();
            vid = new Video();
            vid.attachCamera(cam);
            captureBitmap = new Bitmap(new BitmapData(vid.width, vid.height));
            captureBitmap.x = vid.width;
            addChild(vid);
            addChild(captureBitmap);
            //화면을 클릭할때 마다 캡쳐를 한다.
stage.addEventListener(MouseEvent.CLICK , takePic); //소켓을 생성하고 연결을 잡을 이벤트를 선언한다. socket = new Socket(); socket.addEventListener(Event.CONNECT, connectFn); } //인코딩을 담을 바이트배열 변수 를 선언한다. private var captureByte : ByteArray; private function connectFn(event : Event) : void { //연결이 되었다. 간단한 유효성검사후 전송한다. if (captureByte != null && captureByte.length > 0) { socket.writeBytes(captureByte); socket.flush(); socket.close(); } //연결이 종료되었다. } private function takePic(event : MouseEvent) : void { captureBitmap.bitmapData.draw(vid); captureByte = PngEncoder.encode(captureBitmap.bitmapData); //화면이 클릭되고 캡쳐된 비트맵은 png로 인코딩된다. captureByte.position = 0; //바이트배열 포지션을 처음으로 돌려주고 //소켓을 연결한다. if(socket.connected == false) { //소켓이 연결되면 위에서 선언한이벤트에 의해 connectFn이 실행된다. socket.connect("localhost", 5555); } } } }


아직까지는 as3 에서 버퍼단위로 전송하는 writeByte의 기능은 없는듯하다. 버퍼를 이용하기 위해선
인위적으로 해더 정보를 보내서 서버에서 끝어 읽기 하는 알고리즘이 필요하다
Yamecoder 야매코더_
C# 2011.03.04 18:52

[AxShockwaveFlashObjects] AS3 in C#

 

 

http://www.scripter.co.kr/entry/FlashExternal-c-안에-as3-AVM2-넣기

에서 같은주제를 아주 예전에 다루었지만 내용이 너무 부실하고, 철없었기 때문에 보강을 해야겠다.

사실 구글에 많이 올라와 있는 "AxShockwaveFlashObjects" 관련글들을 그대로 따라했다가는

이유도 모르는 FileNotFoundException 이 나올것이다.

그런 분들은 아래의 DLL 을 사용하기 바란다 .










코드를 살펴 보겠다.



c#



Created with colorer-take5 library. Type 'csharp'

using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Linq;
using System.Text;
using System.Windows.Forms;
using TRACE_Lib;

using Flash.External;
using AxShockwaveFlashObjects;
using System.IO;
using System.Collections;

namespace FlashTEST_1
{
    public partial class Form1 : Form
    {
        public TRACE.TRACE_DELE trace = TRACE.getTrace;
        public Form1()
        {
            InitializeComponent();
        }
        //[0]
        private AxShockwaveFlash flash;
        private ExternalInterfaceProxy proxy;
        
        protected override void OnLoad(EventArgs e)
        {
            //[1]
            flash = new AxShockwaveFlash();
            this.Controls.Add(flash);
            //[2]
            string swfPath = Environment.CurrentDirectory + Path.DirectorySeparatorChar+ "TestCS.swf"; 
            flash.LoadMovie(0, swfPath);
            flash.Width = 500;
            flash.Height = 400;
            //[3]
            proxy = new ExternalInterfaceProxy(flash);
            //[4]
            proxy.ExternalInterfaceCall += new ExternalInterfaceCallEventHandler(proxy_ExternalInterfaceCall);

            base.OnLoad(e);
        }

        object proxy_ExternalInterfaceCall(object sender, ExternalInterfaceCallEventArgs e)
        {
            //[5]
            string name = e.FunctionCall.FunctionName;
            object[] args = e.FunctionCall.Arguments;

            if (name == "ready")
            {
                trace("#", name, (args[0] as ArrayList)[0], (args[0] as ArrayList)[1]);
            }
            //[6]
            if (name == "testCall")
            {
                //[7]
                TxReceive.Text += (args[0] as ArrayList)[0].ToString() + Environment.NewLine;
            }
            //[8]
            return null;
        }

        private void button1_Click(object sender, EventArgs e)
        {
            //[9]
            proxy.Call("CallAS3", TxSend.Text);
        }
    }
}
 
 
/* [0] : Form 으로 플래시를 불러오기위해서는 AxShockwaveFlash 라는 윈도우 컨트롤과 
*       그것을 제어하는 ExternalInterfaceProxy 를 사용하여야 정확하게 AS3과 통신할수 있다.
*
* [1] : flash 컨테이너를 선언하고 메인폼에 붙였다.
*
* [2] : TestCS.swf 의 위치를 획득하여 LoadMovie 하였다.
*
* [3] : 프록시를 선언하여 플래시의 ExternalInterface 과 연결하기로 하였다.
 *
 * [4] : 프록시에 이벤트를 선언하여 플래시에서 오는 신호를 받아 들인다.  *
 * [5] : ExternalInterfaceCallEventArgs 의 멤버로 FunctionCall에서  *       FunctionName 과 Arguments를 얻을수 있다.  *      
 * [6] : "testCall" 은 AS3 코드에서 보면 알겠지만 "Call("testCall" , input.text);" 처럼
 *       서로의 이름이 같게 하여 원하는 값을 추출 한다. 이는 c# 이 값을 받는 상황 과 보내는 상황
*       모두 적용 된다.
*        * [7] : 플래시에서 "...args" 형으로 매개변수를 받는것이 c# 으로 넘어오면 args[0] 로 된다.  *       그리고 그타입은 ArrayList 이다
 *       ※ AS3 의 Array는 배열의 타입을 따로 지정하지 않는 ArrayList 이다.
 *      
 * [8] : 이유는 모르겠지만 라이브러리 상의 이벤트 델리게이트 반환타입이 오브젝트 이어서
 *       불가피하게 return 하였다.  *        * [9] : "[6]"참고 , 플래시로 값을 보낸다.  *  * */
 
 
 
 
그다음은..
AS3






Created with colorer-take5 library. Type 'csharp'

package
{
    import flash.display.Sprite;
    import flash.events.Event;
    import flash.events.MouseEvent;
    import flash.events.TimerEvent;
    import flash.external.ExternalInterface;
    import flash.system.fscommand;
    import flash.text.TextField;
    import flash.text.TextFieldType;
    import flash.utils.Timer;
    
    public class TestCS extends Sprite
    {
        private var tx: TextField;
        private var input : TextField;
        private var bt : Sprite;
        public function TestCS()
        {
            //[0]
            //view..
            tx = new TextField();
            addChild(tx);
            tx.border = true;
            tx.multiline = true;
            tx.width = stage.stageWidth;
            tx.height = stage.stageHeight-50;
            tx.text = "string!";
            
            input = new TextField();
            input.type = TextFieldType.INPUT;
            input.x=  0 ; 
            input.y = tx.y + tx.height + 10;
            input.width = 200;
            input.border = true;
            input.height = 30;
            input.text = "Hellow C#! Iam AS3";
            addChild(input);
            
            bt = new Sprite();
            bt.graphics.beginFill(0x0);
            bt.graphics.drawRect(0,0,100,30);
            bt.x = input.x + input.width + 30;
            bt.y = input.y;
            bt.buttonMode = true;
            addChild(bt);
            
            //[1]
            //Event
            addEventListener(Event.ADDED_TO_STAGE , ready);
            bt.addEventListener(MouseEvent.CLICK , bt_call);
            
            //[2]
            //callback
            CallBack("CallAS3" , callBackFromCSharp);
        }
        
        
        //EventHandler & CallbackMethod
        private function ready(e:Event = null):void
        {
            Call("ready" , stage.stageWidth , stage.stageHeight);
        }
        
        //[3]
        private function callBackFromCSharp(msg : String):void
        {
            tx.text += " \n" + msg;
        }
        
        //[4]
        private function bt_call(e:MouseEvent):void
        {
            Call("testCall" , input.text);
        }
        
        
        //[5]
        //Exception Local Error
        private function Call(ParamName : String ,...args):void
        {
            try{
                ExternalInterface.call(ParamName , args);
            }catch(e:Error){tx.text += e.toString() +"\n";}
        }
        private function CallBack(ParamName : String , CallBack:Function):void
        {
            try{
                ExternalInterface.addCallback(ParamName , CallBack);
            }catch(e:Error){}
        }
    }
}
/**
 * [0] : 화면구성에 필요한 요소들을 생성 , 배치 하였다.
 *
 * [1] : 간단한 문자열을 보낼 버튼 이벤트와 초기화 이벤트를 작성하여 상황에 맞게 c# 으로 값을
 *       보낼것이다.
 *       그러나 초기화 이벤트 (Event.ADDED_TO_STAGE) 는 c# 에서 동작하지 않는다.(?왜그런지..)
 *
 * [2] : c# 에서 올 신호를 받는 콜백을 선언하였다.
 *
 * [3] : "[2]" 를 받는 메서드
 *
 * [4] : 버튼을 누르면 간단히 C# 으로 문자열을 보내는 이벤트 핸들러 "[1]" 참고
 *
 * [5] : 코드를 이처럼 처리한 이유는 swf 를 감싸는 무언가가 없는 상황에서 ExternalInterface 는 에러를 발생시킨다.
 *
 * */


Yamecoder 야매코더_
C# 2011.01.17 18:39

[AS3 , C# ,Serialize]AS3 와 C#의 직렬화 비교

[AS3 , C# ,Serialize]AS3 와 C#의 직렬화 비교



먼저 As3.0( AIR2.0 ) 이다
as.swfcsharp.swf

Created with colorer-take5 library. Type 'csharp'

//c#�� [Serializable] 와 비슷한 개념
[RemoteClass]
public class Test
 {
        private var _str:String = "test";
        public function Test()
        {
            
        }
        
        
        public function get str():String
        {
            return _str;
        }

        public function set str(value:String):void
        {
            _str = value;
        }
}


//\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\





            
            //********************
            // as3(AIR2.0 ) code
            //********************
            private function init():void
            {                            
                
                //--------------------
                //  save data
                // 
                // 임시저장 위��는 :
                // C:\Documents and Settings\<내계정>\Application Data\TestSerialize\Local Store
                // ---------------------
                
                
                var t:Test = new Test;
                t.str = "321321321ㅋㅋㅋㅋ";
                //파일을 만들고
                var savefile:File = File.applicationStorageDirectory.resolvePath("data.dat");
                
                //스트림으로 기록 한다.
                var fileStream:FileStream = new FileStream();
                fileStream.open(savefile , FileMode.WRITE);
                fileStream.writeObject(t);
                fileStream.close();
                t= null;
                
                
                
                
                
                // ----------------
                // load data
                // ------------------ 
                
                //파일위��를 참고��고
                var loadfile:File = File.applicationStorageDirectory.resolvePath("data.dat");
                //존재여부를 판단��여,
                if(loadfile.exists){
                    var _t:Test;
                    var fileStrem:FileStream = new FileStream();
                    //읽고, 
                    fileStream.open(loadfile , FileMode.READ);
                    //타입캐스팅 한다
                    _t = fileStream.readObject() as Test;
                    
                    trace(_t.str);
                }
            }
 
 
 
 
 
 
 
 
 
 
 
그다음은 c# (3.0)
 
 
 
 
 
 
 

 
 
 
 
 
 
Created with colorer-take5 library. Type 'csharp'

// ****************
// c#(3.0) code
// *****************

using System;
using System.Collections.Generic;
using System.Text;
//* 추가된 네임스��이스 **//
using System.IO;
using System.Runtime.Serialization.Formatters.Binary;

namespace ConsoleApplication1
{
    //as3�� [RemoteClass] 와 비슷한개념 //
    [Serializable]
    
    class TestSerilize
    {
        private string str = "test string";
        public String STR
        {
            get{ return str; }
            set { str = value; }
        }
    }


    class Program
    {
        static void Main(string[] args)
        {

            //------------
            // save data
            //------------

            TestSerilize s = new TestSerilize();
            s.STR = "!@!@!zz,zㅋㅋㅋㅋ";
            // 파일을 만들고
            Stream saveFile = new FileStream("data.dat", FileMode.Create, FileAccess.Write , FileShare.None);
            BinaryFormatter bf_save = new BinaryFormatter();
            // 바이너리로 쓴다.
            bf_save.Serialize(saveFile, s);
            saveFile.Close();
            s = null;

            


            //---------
            // loadData
            //-----------
            
            try
            {
                //파일을 읽고,
                Stream loadFile = new FileStream("data.dat", FileMode.Open, FileAccess.Read, FileShare.Read);
                BinaryFormatter bf_load = new BinaryFormatter();
                //바이너리를 읽는다
                TestSerilize _s = (TestSerilize)bf_load.Deserialize(loadFile);
                loadFile.Close();
                Console.WriteLine("deSirialize " + _s.STR);
            }
            catch (IOException e)
            {
                //��시�� ��는,  에러를 ��리한다.
                Console.WriteLine("파일이 없거��..");
            }
        }
    }
}
 
 
 
비슷 하다. 하지만 as3 에서 파일경로를 프로젝트 위치로 하면 보안오류가 발생한다.

(아마 둘의 직렬화 파일을 바꿔치기 하면,, 안되겠지. ㅋ )
Yamecoder 야매코더_
C# 2010.12.04 03:53

[Draw Line Algorithm] 1. 기본(2) 총정리


[Draw Line Algorithm] 1. 기본(2) 총정리



우선 직선의 방정식은 위와 같다. (공통수학의 정석 554p) 두점 p1 , p2 을 알고 있을때 두점의 방정식이다.
m 은 기울기 이다. 즉 x점과 y점의 변화량이다. 그리고 이 공식에는 x1 과 x2는 같지 않을때 이다.
이때는 값이 무한대가 되거나 에러가 난다. 그래서 적절한 예외 처리를 해주어야 한다.



공식을 적용하여 보면 우선 기본적인 m이 -1보다 크고 1보다 작을때 이다. for 루프로 찍혀질
점(자취) _x의 영역을 잡고 범위 안에서 자취_y를 계산 하여 비트맵 데이터의 점을 찍는다.

이때 직선 방정식의 해의 범위가 실수 인데, 우리가 모니터로 보는 모는 비트맵 영역은 정수
이므로 정수로 타입 케스팅 된다
( 사용하는 언어에 따라 자동으로 타입캐스팅이 안되는 경우가 있다 )

이런 식으로 하나하나의 점이 모여 선이 되는것이다.

그러나 이 방법 대로 코딩을 해보면 특정 영역에서는 선이 이루어 지지 않는 경우가 있다.
예시로는 예전의 글의 데모를 보면 알수 있다 http://scripter.egloos.com/2272309 
특히 p0.x 와 p1.x 가 같아질때는 선이 아에 없어 진다.

그래서 범위를 나누어 처리할 필요가 있다. 
노란색 선은 기울기를 말한다. 기초 수학과 차이점은 원점이 좌측 상단이다 그래서 기초수학과 비교하여
기울기가 서로 반대 이다. (2D 의 경우)

점선은 P0.x 와 P1.x 가 같아질 경우 무한대(+- infinity) 혹은 (ZeroDivisionError) 가 발생할경우 인데 요것 역시  
if 로 처리하여 y= P1.x 꼴로 바꾸면 된다.
영역안에 글자는 if 로 처리할 영역의 조건들이다.

우선 P1을 기준으로 오른쪽은 바로 이전의 그림에서 해결하였다. 그리고 P1의 왼쪽영역은 두점의 예외만 처리하면
된다. 문제는 붉은색 영역이다. 붉은색 영역을 기존의 방법 으로 방정식을 풀면 아래의 그림처럼 나온다. 


for 루프는 _x의 영역만 해당하여 X축 에 해당하는 점은 충실히 찍었으나 위의 그림처럼 _x보다 _y가 클때
 선의 점을 모두 충당하지 못하는 경우가 발생한다. 이유는 아까도 말했드시 비트맵은 정수의 영역이기 때문에.
정수로 처리할수 없는 값이 나오기 때문이다.
이럴경우 점선이 되거나 영역을 벗어 나게 된다. 이는 기울기가 급격해 질수록 간격이 벌어져서 수직이 되면
사라지는 현상이 발생한다

이를 해결하기 위해서는 아래의 그림처럼 ...
X축과 Y축을 90도 돌려서 생각하면 된다. 즉 X성분과 Y성분을 를 서로 바꾸어 생각하면 된다.
유의 할점은 기울기 m 도 x성분과 y성분을 바꾸면 1/m 이 된다. 

위의 구차한? 설명들은 코드로 한방에 생각해 보자
코드를 보면 쉽다.

circle클래스는 단순한 Sprite 에 원을 그리고 글자를 넣은 단순한 클래스 이다.


위의 코드를 컴파일 하면
영역별로 선 색깔을 다르게 했다.

'수학' 카테고리의 다른 글

[Draw Line Algorithm] 1. 기본(2) 총정리  (90) 2010.12.04
[Draw Line Algorithm] 1. 기본(1)  (65) 2010.12.04
[회전변환] 특정좌표를 중심으로 회전변환  (122) 2010.12.04
[삼각함수] 기울어진 그리드의 좌표 구하기  (39) 2010.12.04
정렬  (45) 2010.12.04
atan2 를 "도" 로 환산  (200) 2010.12.04
Yamecoder 야매코더_
수학 2010.12.04 03:40

[Draw Line Algorithm] 1. 기본(1)


[Draw Line Algorithm] 1. 기본(1)

XNA 에 별다른 비트맵 API가 없다는것을 알고 , 한번 픽셀을 다루기로 했다.

우선 브레슨햄 알고리즘 에 들어가기 전에 일반적인 선을 그리는 알고리즘을

살펴 보아야 하겠다.

먼저 우리가 비트맵에 선을 긋기 위해서는 일반적으로 두점을 필요로 한다. 
(물론 한점과 기울기를 이용할수도 있겠지만 특별한 경우가 아니라면 정확한 포인팅이 가능한 두점을 이용한다)  

우선 고등학교 기초 수학에 보면 두점을 알때 직선 방정식은 ..

(공통수학의 정석 p554)

p0(x0 , y0) 와 p1(x1,y1) 을 알때 직선의 방정식은 

Y - y0 = ( y1 - y0 / x1 - x0 ) * ( X - x0)  (단 , x1  !=  x0)

이러하다. 기본적인 Y = m*X 라는 공식에 대힙하면  ( y1 - y0 / x1 - x0 ) 이 기울기 이자

변화량 이란것쯤은 알수있다. 나머지 Y - y0  ,  X - x0  은 평행 이동 이다.

누구나 알고 있을법한 이 방정식을 비트맵 위에 표현해보자.

우선 비트맵은 정수들 "맵" 이다, 위의 공식의 영역은 "실수" 이다.

따라서 정수로 다운캐스팅 하여 표현 해야 한다.


이제 한번 본격적으로 for 루프를 생각해 보자

기본적으로 X 축 변화량을 생각하면 범위를 쉽게 생각할수 있다.
이다. 따라서 for 루프는 다음과 같이 될수 있겠다.

for( var _x:int =p0.x   ; _x < p1.x  ; ++_x)
{
    //
}


이것으로 공식의 우변 _x 를 설정 했다. 그리고 이것을 Y에 넣기 전에 기울기 m을 설정하자

var m:Number = (p1.y-p0.y)/(p1.x-p0.x);

이다

이제 루프를 완성하면

for( var _x:int =p0.x   ; _x < p1.x  ; ++_x)
{
     var _y:int =Math.round(m*(_x-p0.x) + p0.y);
     data.setPixel(_x,_y,0);
}


완성하면 여기서 dataBitmapData 이다.

그리고 위의 직선 공식을 정리하면 _y 값을 얻을수 있는데 

아까도 말했드시 비트맵은 정수를 사용하여서  round 로 반올림을 하여 정수화 했다.

이 공식을 이용하여 간단히 프로그래밍 해보면,.

Bresenham1_as.swf

p0 와 p1을 직접 움직여 보자



와 같은 결과를 낸다.  ( 브라우저에서 해보기 보단 직접 다운하여 로컬에서 추천)

그런데 조건이 있다.

1.
Y - y0 = ( y1 - y0 / x1 - x0 ) * ( X - x0)  (단 , x1  !=  x0)
에서의 조건인데 p0.x 와 p0.y 가 같으면 안되고

2.
또한 위의 결과물에서는 기울기가 (-) 이 되었을때 , 즉( p0.x > p1.x ) 가 되었을때,

3.
x의 변화량 보다 y의 변화량이 클때 , 즉 기울기가 1 보다 클때 비트맵의 양 조절


이렇게 3개 이고 이것에 대해 파생되는 여러 예외를 제어 해야 한다.

'수학' 카테고리의 다른 글

[Draw Line Algorithm] 1. 기본(2) 총정리  (90) 2010.12.04
[Draw Line Algorithm] 1. 기본(1)  (65) 2010.12.04
[회전변환] 특정좌표를 중심으로 회전변환  (122) 2010.12.04
[삼각함수] 기울어진 그리드의 좌표 구하기  (39) 2010.12.04
정렬  (45) 2010.12.04
atan2 를 "도" 로 환산  (200) 2010.12.04
Yamecoder 야매코더_
수학 2010.12.04 03:39

[회전변환] 특정좌표를 중심으로 회전변환


[회전변환] 특정좌표를 중심으로 회전변환

점 S 를 중심으로 점 P 를 R 만큼 회전 하였을때 P' 의 좌표를 구하는 공식!

회전변환 행렬을 보면 이러하다,.


그리고 이것을 정리하면

x' = (x-a) * cosR - (y-b)sinR
y' = (x-a) * sinR + (y-b)cosR

이것을 메소드로 만들면..


            private function init():void
               {
                    //특정 오브젝트 sp 의 원래 좌표
                    sp.x = 100
                    sp.y = 100

                    var ob:Object = transformation(0,0,sp.x,sp.y,30*Math.PI/180)   
                    trace(ob.x , ob.y)

                    sp.x = ob.x
                    sp.y = ob.y
               }

               private function transformation(cx:Number,cy:Number,
                                                  px:Number,py:Number,
                                                  rad:Number):Object
               {

                    var rx:Number = (px-cx)*Math.cos(rad) - (py-cy)*Math.sin(rad) + cx;
                    var ry:Number = (px-cx)*Math.sin(rad) + (py-cy)*Math.cos(rad) + cy;                 
                    return {x:rx , y:ry}     
               }

와 같이 좌표를 변환할수 있다.

그리고 참고자료
transformation.PDF 을 참고 하면 증명이 될것이다. 고등학교 수학이다.
문득 고등학교 수학선생님이 생각난다. 회전변환이 중요하다고는 하는데 그때당시 이유를
몰랐다. 하지만 프로그래밍을 하고 있는 요즘 그때 생각이 절로 난다.

그리고 약간 어눌하지만 칠판에 쉽게 그리는 3차원 변환좌표와 도형을 그리는 고등학교때
수학선생님은 지금 생각하건데 천재였다. 당시 코싸인과 싸인의 연속, 역함수와 행렬의
연속인 수식은 오늘날 생각하면 3D의 기초 로직이었다.

당시 선생님은 그러한것을 알고 가르치신 건지는 모르겠다만.
내가 기억하는 고등학교 수학선생님은 수업 시작시 수학책 한번만 보고 바로 덮는다.

그리고  예제나 질문을 칠판과 분필을 이용해 풀이했다. 엄청난 악필이었다.
하지만 다른 수학선생님들과 다르게 막힘이나 오답이 거의 없었다. 나이도 꾀 있으셨는데..
그래서인지 약간 고등학교 수준을 벗어나는 3차원 미적분 까지 경험?할수 있었던것같다.


'수학' 카테고리의 다른 글

[Draw Line Algorithm] 1. 기본(2) 총정리  (90) 2010.12.04
[Draw Line Algorithm] 1. 기본(1)  (65) 2010.12.04
[회전변환] 특정좌표를 중심으로 회전변환  (122) 2010.12.04
[삼각함수] 기울어진 그리드의 좌표 구하기  (39) 2010.12.04
정렬  (45) 2010.12.04
atan2 를 "도" 로 환산  (200) 2010.12.04
Yamecoder 야매코더_
수학 2010.12.04 03:38

[PageFlip] Foxy의 PageFlip을 이용한 책갈피 영역의 제한 로직


[PageFlip] Foxy의 PageFlip을 이용한 책갈피 영역의 제
한 로직
Yamecoder 야매코더_
tags : AS3, flash, Flex, pageFlip
수학 2010.12.04 03:37

원의 자취 구하기


원의 자취 구하기 수학


각도 sin(angle) = 높이(b) / 빗면(c)
각도 cos(angle)= 밑면(a) / 빗면(c)

밑면(a) = cos(angle)* 빗면(c)
높이(b) = sin(angle) * 빗면(c)

p1.x = cos(angle) *빗면(c)
p1.y = sin (angle) *빗면(c)

기초에 충실하자! 고등학교때 '얼싸안코' 가 생각난다.


또한 이를 응용하여 가로 세로 값을 알고 있을때는..

tan( angle ) = height/width
이고 , 각을 알기 위해 tan 를 넘겨야한다.

( angle ) = atan( height/width )
넘길때는 tan의 역수인 atan으로 넘긴다.

angle을 cos , sin 에 대입하여 푼다



또한 원의 중심점을 옮겨 자취를 구해야 할 상황이 생긴다.

                    var cx:Number = 100 // 가로로 움직일 양
                    var cy:Number = 100 // 세로로 움직일 양
                    var theta:Number = Math.atan2(mouseY - cy , mouseX - cx)
                    var p:Point = CirclePosition(theta , 100 , cx , cy)
                   
                    ob.x = p.x
                    ob.y = p.y

                   function CirclePosition( theta:Number,Radius:Number=100,cx:Number=0,cy:Number=0 ):Point
                  {
                          var tx:Number = cx+Radius*Math.cos(theta);
                          var ty:Number = cy+Radius*Math.sin(theta);
                          return new Point(tx,ty);
                  }

 만약 타원을 원한다면 tx 와 ty 의 반지름을 달리하면 된다!
Yamecoder 야매코더_
수학 2010.12.04 03:36

[drawTriangles] 가장?쉬운 삼각형 응용 예제



 


testTriangle.zip

테스트 코딩이다.



Yamecoder 야매코더_
AS3 2010.12.04 02:41

[bitmapData Capture] stage capture 시 유의점

상황은 트위너로 5개의 cicle을 랜덤하게 트위닝 하고,
그것을 엔터프레임으로 비트맵 데이터로 캡춰를 하는 상황이다.

그리고 엔터프레임 안에는 기본적으로 아래와 같이 작성을 한다.

//in EnterFrame
capture = new BitmapData(stage.stageWidth, stage.stageHeight , false ,0xd0d0d0)
capture.draw(stage)
//

그럼 결과는


하지만 이것은 원하는결과가 아니다.
잔상이 없는 결과를 원하면 스테이지에 바로 addChild하지말고
컨테이너를 하나 만든다음 해줘야 한다.

//in EnterFrame
capture = new BitmapData(stage.stageWidth, stage.stageHeight , false ,0xd0d0d0)
capture.draw(contaner) // contaner 는 Sprite 인스턴스이다.
//

결과는



테스트 코드는 captureTest.txt
Yamecoder 야매코더_
AS3 2010.12.04 02:41

[Simple Text Writer V0.1] 간편한 파일 쓰기 어플


간편한 파일 쓰기 어플



client code (AS3)

flush 규칙!


         파일경로(filePath):::내용(content) + "\n"

(':::' 요걸로 파일경로와 내용을 구분합니다.)


ex >> "c:\\sampleFolder\\childFolder\\content.xml"
         +":::
         +xml.toString()
         +"\n";


그냥 자기 컴퓨터에서 돌아가는 로컬용 입니다.(웹은 당연 안돌아가겠죠)
대용량은 테스트 안해봤습니다.
하루 종일 돌려보진 않았습니다.
피드백은 덧글로..
버전업은 할수 있을지. ,, 과연 = =;
옵션도 넣고 하려 했지만.. 일을 줄이기 위해 만드는건데, 이게 더 일이 될것 같아서 딱 필요한것만 구현했습니다.
Yamecoder 야매코더_
C# 2010.12.04 02:35

[socket] c# server , as3 client


pc1 ( server ): c# (windows 7)








pc2 ( client ) : AS3 (windows xp)



c# code (partial)



Created with colorer-take5 library. Type 'csharp'

/*
 * SharpDevelop으로 작성��었습니다.
 * 사용자: jjongun
 * 날짜: 2010-02-09
 * 시간: ��전 9:05
 * 
 * 
 */
using System;
using System.Collections.Generic;
using System.Drawing;
using System.Windows.Forms;
using System.Threading;
using System.Net.Sockets;
using System.Net;
using System.IO;
using System.Diagnostics;
using System.Timers;


namespace testServer3
{
    /// <summary>
    /// Description of MainForm.
    /// </summary>
    public partial class MainForm : Form
    {
        public MainForm()
        {
            //
            // The InitializeComponent() call is required for Windows Forms designer support.
            //
            InitializeComponent();
            
            //
            // TODO: Add constructor code after the InitializeComponent() call.
            //
        }
        private delegate void serverMrgDele(string str);
        private System.Timers.Timer catchClient;
        private System.Timers.Timer readTimer;
        private IPAddress address;
        private Int32 port;
        private TcpListener server;
        private serverMrgDele mrg;
        private TcpClient client;
        private StreamWriter writer;
        private StreamReader reader;
        private NetworkStream stream;
        
        private Thread serverThread;
        private Thread checkThread;
        private Thread readThread;
        void ConnectBtClick(object sender, EventArgs e)
        {
            if(ipTx.Text == "")
                ipTx.Text = "127.0.0.1";
            if(portTx.Text == "")
                portTx.Text = "1000";
            try{
                address = IPAddress.Parse(ipTx.Text);
                port = Convert.ToInt32(portTx.Text);
            }catch(FormatException fe)
            {
                Trace.WriteLine(fe);
                ipTx.Clear();
                portTx.Clear();
            }
            
            mrg = new serverMrgDele(traceBox.AppendText);
            
            Thread serverThread = new Thread( new ThreadStart(startServer));
            readThread = new Thread(new ThreadStart(readClinet));
            checkThread = new Thread(new ThreadStart(checkClinetStatus));
            serverThread.Start();
        }
        
        //thread1
        private void startServer()
        {
            server = new TcpListener(address , port);
            Invoke(mrg , "start" + Environment.NewLine);
            server.Start();
            client = server.AcceptTcpClient();
            Invoke(mrg , "client connect" + Environment.NewLine);
            stream = client.GetStream();
            
            writer = new StreamWriter(stream);
            
            readThread.Start();
            checkThread.Start();
        }
        
        //thrad2
        private void readClinet()
        {
            reader = new StreamReader(stream);
            readTimer = new System.Timers.Timer();
            readTimer.Elapsed+= new ElapsedEventHandler(readTimer_Elapsed);
            readTimer.Interval=100;
            readTimer.Start();
        }
        
        void readTimer_Elapsed(object sender, ElapsedEventArgs e)
        {
            Invoke(mrg , reader.ReadLine() + Environment.NewLine);
        }
        
        
        
        //thread3
        private void checkClinetStatus()
        {
            catchClient = new System.Timers.Timer();
            catchClient.Elapsed += new ElapsedEventHandler(catchClient_Elapsed);
            catchClient.Interval = 100;
            catchClient.Start();
        }

        void catchClient_Elapsed(object sender, ElapsedEventArgs e)
        {
            //????
            //Trace.WriteLine(client.Connected);
        }
        
                
        private int checknum = 0;
        void SendBtClick(object sender, EventArgs e)
        {
            checknum ++ ;
            if(sendTx.Text =="")
                sendTx.Text = "mrg form C#" + checknum.ToString();
            writer.WriteLine(sendTx.Text + "\n");
            writer.Flush();
        }
        
        void DisconnectBtClick(object sender, EventArgs e)
        {
            try{
                client.Close();
            }catch( Exception ex){}
            writer.Close();
            reader.Close();
            server.Stop();
        }
    }
}
 
 
 
 
 
 AS3 code (flex4)
 
 
 
 
 
 
 
 
 
<?xml version="1.0" encoding="utf-8"?>
<s:Application xmlns:fx="http://ns.adobe.com/mxml/2009" 
               xmlns:s="library://ns.adobe.com/flex/spark" 
               xmlns:mx="library://ns.adobe.com/flex/halo" minWidth="1024" minHeight="768"
               width="299" height="522">

    <fx:Script>
        <![CDATA[
            
            private var client:Socket;
            protected function connetBt_clickHandler(event:MouseEvent):void
            {
                
                client = new Socket;
                
                if(ipTx.text == "")
                    ipTx.text = "127.0.0.1";
                if(portTx.text == "")
                    portTx.text = "1000";
                
                client.connect(ipTx.text , int(portTx.text));
                client.addEventListener(Event.CONNECT , serverConnect);
                client.addEventListener(ProgressEvent.SOCKET_DATA , onData);
                client.addEventListener(Event.CLOSE , disconnect);
                
                // TODO Auto-generated method stub
            }
            private function serverConnect(e:Event):void
            {
                traceBox.appendText("connect server" + "\n");
            }
            private function onData(e:ProgressEvent):void
            {
                trace("data");
                traceBox.appendText("c#Mrg : " + client.readUTFBytes(client.bytesAvailable) + "\n");
            }
            private function disconnect(e:Event):void
            {
                traceBox.appendText("close server" +"\n");
                client.close();
            }

            protected function sendBt_clickHandler(event:MouseEvent):void
            {
                if(sendTx.text == "")
                    sendTx.text = "mrg from As3";
                client.writeUTFBytes(sendTx.text + "\n");
                client.flush();
            }

        ]]>
    </fx:Script>

    <fx:Declarations>
        <!-- Place non-visual elements (e.g., services, value objects) here -->
    </fx:Declarations>
    <s:TextArea x="10" y="89" width="279" height="276" id="traceBox"/>
    <s:TextArea x="11" y="390" width="279" height="26" id="sendTx"/>
    <s:TextArea x="10" y="10" height="24" width="149" id="ipTx"/>
    <s:TextArea x="167" y="10" height="24" width="122" id="portTx"/>
    <s:Button x="10" y="42" label="connect" width="279" id="connetBt" click="connetBt_clickHandler(event)"/>
    <s:Button x="10" y="474" label="disconnect" width="279" id="disconnectBt"/>
    <s:Button x="10" y="425" label="sendMrg" width="279" id="sendBt" click="sendBt_clickHandler(event)"/>
</s:Application>
 
 
 
c#에서는 stream을 readLine 으로 받는다. 따라서 
as3 에도 string 값을 "  somstring  " + " \n" 으로 줄을 넘겨줘야 c#에서 read 할수 있다.
Yamecoder 야매코더_
tags : AS3, c#, Flex, socket
C# 2010.12.04 00:14
Powerd by Tistory, designed by criuce
rss