/* VB
             Private Sub dgvLegends_CellPainting(ByVal sender As Object, ByVal e As System.Windows.Forms.DataGridViewCellPaintingEventArgs) Handles dgvLegends.CellPainting
        'Draw custom cell borders.
        'If current column is DisplayName...
        If dgvLegends.Columns("DisplayName").Index = e.ColumnIndex AndAlso e.RowIndex >= 0 Then
                Dim Brush As New SolidBrush(dgvLegends.ColumnHeadersDefaultCellStyle.BackColor)
                e.Graphics.FillRectangle(Brush, e.CellBounds)
                Brush.Dispose()
                e.Paint(e.CellBounds, DataGridViewPaintParts.All And Not DataGridViewPaintParts.ContentBackground)

                ControlPaint.DrawBorder(e.Graphics, e.CellBounds, dgvLegends.GridColor, 1, ButtonBorderStyle.Solid, dgvLegends.GridColor, 1, ButtonBorderStyle.Solid, dgvLegends.GridColor, 1, ButtonBorderStyle.Solid, dgvLegends.GridColor, 1, ButtonBorderStyle.Solid)

            e.Handled = True
        End If
    End Sub
             */
            if (e.RowIndex == 0 || e.ColumnIndex == 0)
            {
                Brush b = new SolidBrush(Color.Black);
                e.Graphics.FillRectangle(b, e.CellBounds);
                b.Dispose();
                e.Paint(e.CellBounds, DataGridViewPaintParts.All | DataGridViewPaintParts.ContentBackground);
                ControlPaint.DrawBorder(e.Graphics, e.CellBounds, Color.Black, 0, ButtonBorderStyle.Outset,
                    Color.Black, 0, ButtonBorderStyle.Outset, Color.Black, 1,
                    ButtonBorderStyle.Outset, Color.Black, 1, ButtonBorderStyle.Outset);
                e.Handled = true;
            }

e.Paint의 매개변수를 잘살펴봐서 적용 시켜야 한다.

 

한개의 Cell의 Border를 변경하는게 아니라서

Border가 겹쳐서 이상하게 보이는 문제 해결한 코드이다.

 

위의 코드에서는

left와 top의 선의 크기를 0으로 주어서

Border를 겹치지 않게 그리고 있다.

회사에서 delphi소스 보면서 프로젝트 진행하는게 있어서..........

선 위에 마우스 좌표가 존재하는지 판별 하는 알고리즘이다~

식이 궁금한데.........아~~~~~중학 수학부터 책사서 공부해야겠다ㅜㅠ

 

 

 

                               #region 델파이소스 (선 판별)
                                /*
                                function PtOnLine(const P1: TPoint; const P2: TPoint;
                                  const P: TPoint; const Ptol: Integer): Boolean;
                                {-------------------------------------------------------}
                                {  Checks if point P is on line between points P1 & P2  }
                                {-------------------------------------------------------}
                                var
                                  dx,  dy  : Integer;
                                  dx1, dy1 : Integer;
                                  a, b, c  : Integer;
                                begin
                                  Result := False;
                                  dx := P2.X - P1.X;
                                  dy := P2.Y - P1.Y;
                                  dx1 := P.X - P1.X;
                                  dy1 := P.Y - P1.Y;
                                  if (Abs(dx) > 0) and (Abs(dy) < Abs(dx)) then
                                  begin
                                    if (dx*dx1 >= 0) and (Abs(dx1) <= Abs(dx)) then
                                    begin
                                      a := (dy*dx1);
                                      b := (dx*dy1);
                                      c := Abs(dx*Ptol);
                                      if Abs(a-b) <= c then Result := True;
                                    end;
                                  end
                                  else if Abs(dy) > 0 then
                                  begin
                                    if (dy*dy1 >= 0) and (Abs(dy1) <= Abs(dy)) then
                                    begin
                                      a := (dx*dy1);
                                      b := (dy*dx1);
                                      c := Abs(dy*Ptol);
                                      if Abs(a-b) <= c then Result := True;
                                    end;
                                  end;
                                end;*/

                                #endregion
                                Point startP = link.Locations[j];
                                Point endP = link.Locations[j+1];
                                int dx = endP.X - startP.X;
                                int dy = endP.Y - startP.Y;
                                int dx1 = point.X - startP.X;
                                int dy1 = point.Y - startP.Y;
                                int a = 0, b = 0, c = 0;
                                if (Math.Abs(dx) > 0 && Math.Abs(dy) < Math.Abs(dx))
                                {
                                    if (dx * dx1 >= 0 && Math.Abs(dx1) <= Math.Abs(dx))
                                    {
                                        a = (dy * dx1);
                                        b = (dx * dy1);
                                        c = Math.Abs(dx * ptol);
                                        if (Math.Abs(a - b) <= c)
                                        {
                                            iDraw = link;
                                            return iDraw;
                                        }
                                    }
                                }
                                else if (Math.Abs(dy) > 0)
                                {
                                    if (dy * dy1 >= 0 && (Math.Abs(dy1) <= Math.Abs(dy)))
                                    {
                                        a = (dx * dy1);
                                        b = (dy * dx1);
                                        c = Math.Abs(dy * ptol);
                                        if (Math.Abs(a - b) <= c)
                                        {
                                            if (Math.Abs(a - b) <= c)
                                            {
                                                iDraw = link;
                                                return iDraw;
                                            }
                                        }
                                    }
                                }


 

 

 

Wave

파일 분석

 

 

 

 

 

 

 

 

 

 

 

 

 

 

선문비트예비 21기

김동영

목 차

 

 

  • Wave 파일이란?

 

  • Wave 포맷 구성

 

  • Wave 포맷 분석

 

  • Wave 포맷 분석 구현

 

 

  • Wave 파일이란?

 

Wave 파일이란 마이크로소프트와 IBM의 오디오 파일 포맷 표준으로 윈도우에서 표준적으로 사용되는 PCM데이터 파일입니다. PCM이란 아날로그 신호를 디지털 신호로 바꾸어주는 방식입니다.

 

 

 

 

  • Wave 포맷구성

윈도우의 녹음기를 통하여 녹음 하였을 때, 생성되는 wave파일의 포맷입니다.

맨 처음 RIFF chunk로 시작하여 FMT chunk, FACT chunk, Data chunk가 오게 되는데

FACT chunk는 존재 할 수도 있고 존재 하지 않을 수도 있습니다.

기본적으로는 RIFF chunk, FMT chunk, Data chunk로 이루어져있습니다.

 

 

 

 

 

  • Wave 포맷 분석

1) RIFF chunk

내용

type

byte

의미

"RIFF"

char

4

파일의 종류가 RIFF 파일을 의미

FileSize

DWORD

4

현재부터 끝까지의 파일 크기

"WAVE"

char

4

Wave 파일을 의미

 

2) FMT sub-chunk

내용

type

byte

의미

"fmt"

char

4

Chunk ID

16 | 18

DWORD

4

Chunk Size

wFormatTag

short

2

PCMWAVEFORMAT의 값(1:PCM )

nChannels

short

2

채널수(1:모노, 2:스테레오)

nSamplesPerSec

DWORD

4

샘플링 수

nAvgBytesperSec

DWORD

4

초당 샘플 바이트

SampleSize

short

2

샘플당 바이트

wBitsPerSample

short

2

샘플당 비트수

ExtraFormatBytes

short

2

여분의 바이트를 의미함

ExtraFormatBytes는 Chunk Size가 18일 때만 존재합니다.

 

 

3) FACT sub-chunk

내용

type

byte

의미

"fact"

char

4

Chunk ID

4

DWORD

4

Chunk Size

SampleLength

DWORD 

4

샘플의 길이

FACT sub-chunk는 존재 할 수도 있고 존재하지 않을 수도 있습니다.

 

 

4) Data sub-chunk

내용

type

byte

의미

"data"

char

4

Chunk ID

DATA SIZE

DWORD

4

데이터의 크기

DATA

  

  

데이터

 

 

  • Wave 포맷 분석 구현

 

SoundInfo 클래스는 RIFF Chunk(ParentChunk 클래스)와 FMT Sub-Chunk(SubChunk 클래스)와 Data Sub-Chunk(DataChunk)를 관리해주는 클래스입니다.

 

SoundInfo.cpp

생성자에서 각각의 Chunk별로 데이터들을 얻습니다.

SoundInfo::SoundInfo(HANDLE hFile)

{

    parent_chunk=new ParentChunk(hFile);

    sub_chunk=new SubChunk(hFile);

    data_chunk=new DataChunk(hFile);

}

 

ParentChunk의 데이터를 얻어옵니다.

//===================ParentChunk========================

char *SoundInfo::GetFiletype()

{

    return parent_chunk->GetFiletypeC();

}

int SoundInfo::GetFilesize()

{

    return parent_chunk->GetFilesizeC();

}

char *SoundInfo::GetMediatype()

{

    return parent_chunk->GetMediatypeC();

}

 

//=====================================================

 

각 Chunk별로 Wave파일의 속성이 맞는지 확인합니다.

 

bool SoundInfo::CheckParentChunk()

{

    return parent_chunk->IsAvailChunk();

}

bool SoundInfo::CheckSubChunk()

{

    return sub_chunk->IsAvailChunk();

}

bool SoundInfo::CheckDataChunk()

{

    return data_chunk->IsAvailChunk();

}

 

 

SubChunk의 데이터를 얻어옵니다.

 

//===================SubChunk========================

 

 

char *SoundInfo::GetMagic()//매직

{

    return sub_chunk->GetMagicC();

}

int SoundInfo::GetPt()

{

    return sub_chunk->GetPtC();

}

short SoundInfo::GetFormat()//포맷

{

    return sub_chunk->GetFormatC();

}

short SoundInfo::GetChannelcnt()//채널수

{

    return sub_chunk->GetChannelcntC();

}

int SoundInfo::GetSamples_persec()//초당샘플수

{

    return sub_chunk->GetSamples_persecC();

}

int SoundInfo::GetBytes_persec() //초당바이트수- 평균값임

{

    return sub_chunk->GetBytes_persecC();

}

short SoundInfo::GetSize_sample() //샘플1개의사이즈

{

    return sub_chunk->GetSize_sampleC();

}

short SoundInfo::GetBits_persample()//샘플한개의비트수

{

    return sub_chunk->GetBits_persampleC();

}

short *SoundInfo::GetSize_extend()//옵션의사이즈

{

    return sub_chunk->GetSize_extendC();

}

//=====================================================

 

 

 

 

 

 

 

DataChunk의 데이터를 얻어옵니다.

 

//===================DataChunk========================

 

char *SoundInfo::GetDataMagic()

{

    return data_chunk->GetDataMagicC();

}

int SoundInfo::GetDataSize()

{

    return data_chunk->GetDataSizeC();

}

short* SoundInfo::GetData()

{

    return data_chunk->GetDataC();

}

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

ParentChunk.cpp

Filetype,filesize,mediatype을 읽어옵니다.

 

ParentChunk::ParentChunk(HANDLE hFile)

{

    DWORD dwRead;

    ReadFile(hFile,filetype,4,&dwRead,0);

    ReadFile(hFile,&filesize,4,&dwRead,0);

    ReadFile(hFile,mediatype,4,&dwRead,0);

}

 

 

 

만약 filetype이 "RIFF"이 아니거나 mediatype이 "WAVE"가 아닌 경우 0을 리턴합니다.

 

bool ParentChunk::IsAvailChunk()

{

return (strcmp(MAGIC_FILE_TYPE,filetype)==0)&&(strcmp(MAGIC_WAVE_TYPE,mediatype)==0);

}

 

char *ParentChunk::GetFiletypeC()

{

    return filetype;

}

int ParentChunk::GetFilesizeC()

{

    return filesize;

}

char *ParentChunk::GetMediatypeC()

{

    return mediatype;

}

 

 

 

 

 

 

 

 

 

 

 

 

SubChunk.cpp

 

ChunkID,ChunkSize, PCMWAVEFORMAT의 값,채널수,샘필링수,초당 샘플 바이트,샘플당 바이트, 샘플당 비트수를 얻어옵니다.

Pt의 값(chunk size)이 18일 경우에는 옵션의 사이즈와 fact chunk가 존재합니다.

 

SubChunk::SubChunk(HANDLE hFile)

{

    DWORD dwRead;

    ReadFile(hFile,magic,4,&dwRead,0);

    ReadFile(hFile,&pt,4,&dwRead,0);

    ReadFile(hFile,&format,2,&dwRead,0);

    ReadFile(hFile,&channelcnt,2,&dwRead,0);

    ReadFile(hFile,&samples_persec,4,&dwRead,0);

    ReadFile(hFile,&bytes_persec,4,&dwRead,0);

    ReadFile(hFile,&size_sample,2,&dwRead,0);

    ReadFile(hFile,&bits_persample,2,&dwRead,0);

    //pt1618이아닌경우는배제

    if(pt==18 )

    {

        ReadFile(hFile,&extra_formatbytes,2,&dwRead,0);

        ReadFile(hFile,fmagics,4,&dwRead,0);//fact chunk

        ReadFile(hFile,&fackchunk_size,4,&dwRead,0);

        ReadFile(hFile,&sample_length,4,&dwRead,0);

    }

}

 

 

 

 

 

 

ChunkID(magic)이 "fmt"이 아니거나 format(PCMWAVEFORMAT)값이 1(Wave Format이 PCM 방식) 이 아닐 때 0을 리턴합니다.

bool SubChunk::IsAvailChunk()

{

    return (strcmp(MAGIC_SUB_TYPE,magic)==0)&&(format==PCMWAVE_FORMAT);

}

 

 

 

 

 

 

char *SubChunk::GetMagicC()//ChunkID

{

    return magic;

}

int SubChunk::GetPtC()//ChunkSize

{

    return pt;

}

short SubChunk::GetFormatC()//포맷

{

    return format;

}

short SubChunk::GetChannelcntC()//채널수

{

    return channelcnt;

}

int SubChunk::GetSamples_persecC()//초당샘플수

{

    return samples_persec;

}

int SubChunk::GetBytes_persecC() //초당바이트수- 평균값임

{

    return bytes_persec;

}

short SubChunk::GetSize_sampleC() //샘플1개의사이즈

{

    return size_sample;

}

short SubChunk::GetBits_persampleC()//샘플한개의비트수

{

    return bits_persample;

}

short *SubChunk::GetSize_extendC()

{

    return size_extend;

}

 

 

 

 

 

 

 

 

 

 

 

 

DataChunk.cpp

 

 

ChunkID,DataSize,Data를 얻어옵니다.

DataChunk::DataChunk(HANDLE hFile)

{

    DWORD dwRead;

    ReadFile(hFile,magic,4,&dwRead,0);

    ReadFile(hFile,&datasize,4,&dwRead,0);

    data=(short *)malloc(datasize);

    short _data;

    int j=0;

    for(int i=0;i<datasize;i=i+2)

    {

        ReadFile(hFile,&_data,sizeof(short),&dwRead,0);

        data[j]=_data;

        if(dwRead == 0)

        {

            break;

        }

        j++;

    }

}

 

 

ChunkID가 "DATA"가 아니면 0을 리턴합니다.

 

bool DataChunk::IsAvailChunk()

{

    return (strcmp(MAGIC_DATA_TYPE,magic)==0);

}

 

char *DataChunk::GetDataMagicC()

{

    return magic;

}

int DataChunk::GetDataSizeC()

{

    return datasize;

}

short* DataChunk::GetDataC()

{

    return data;

}

 

 

Analysis.cpp

 

Analsis 클래스는 입력한 신호의 chunk 데이터에서 얻은 수치에 대한 평균 세기, 총 에너지, 총 주파수를 계산합니다.

 

 

평균 세기는 데이터값의 절대값들의 총 합에서 데이터 개수를 나누어주면 됩니다.

 

int Analysis::GetPower(short *data,int datasize)

{

    unsigned temp=0;

    for(int i=0;i<datasize/2;i++)

    {

        if(data[i]<0)

        {

            data[i]=data[i]*-1;

        }

        temp=temp+data[i];

    }

    

    return temp/(datasize/2);

}

 

 

 

총 에너지는 데이터값의 절대값들의 절대값들의 총 합에서 데이터 개수를 곱해주면 됩니다.

 

int Analysis::GetEnergy(short *data,int datasize,HWND hDlg)

{

    int temp=0;

    for(int i=0;i<datasize/2;i++)

    {

        if(data[i]<0)

        {

            data[i]=data[i]*-1;

        }

        temp=temp+data[i];

    }

    return ((temp/1000000)*(datasize/2));

}

 

 

 

 

 

 

 

 

 

 

 

총 주파수는 처음 데이터 값과 다음 데이터 값을 비교해 한 주기는 dcnt가 2개 증가 하였을때이므로 총 주파수는 dcnt/2를 리턴합니다.

 

int Analysis::GetFrequency(short *data,int datasize)

{

    int size=datasize/2;

    bool direction=true;

    int old = 0;

    int dcnt = 0;

 

    for(int i=0;i<size;i++)

    {            

        if(direction)//현재증가하는경우라면

        {

            if(data[i]>old) //새로운값이기존값보다크다면방향유지

            {

            }

            else    //방향이바뀌었음

            {

                direction = false;

                dcnt++;

            }

        }

        else

        {

            if(data[i]<old)

            {

            }

            else

            {

                direction = true;

                dcnt++;

            }

        }

        old = data[i];

    }

 

    return dcnt/2;

}

 

 

 

 

[21기_김동영]wave파일_분석_기술문서[1].doc

 

 

'기타 > Wave' 카테고리의 다른 글

Wave파일 구조  (0) 2012.11.02
주파수 생성  (0) 2012.08.16

학습 내용

조 : 2조

작성자 : 김동영

작성일 : 2011. 5. 29

제목 : Wave 포맷 분석

 

 

1. Wave파일이란?

기본적으로 MS사의 기본 Sound Format이다.

전체 구조는 Electronic Arts사의 IFF(Interchange File Format)에 기초를 두고 있고, MS사의 RIFF(Resource IFF)와 Apple의 AIFF로 나뉜다.

 

wave파일의 구조는 다음과 같다.

오른쪽 숫자는 읽어야 할 byte, *은 가변적인 길이이다.

 

 

 

 

 

2. Chunk의 기본형식

chunk의 기본형식은 다음과 같다.

 

 

 

Chunk ID가 있고, 해당 Chunk의 Size, Size만큼의 Data가 들어있다.

 

3. fmt_ Chunk

해당 Chunk는 이 wave파일의 정보들을 보관하고 있다.

 

"fmt_"

Chunk ID

Chunk Size

Chunk Size

Compression Code

PCMWAVEFORMAT의 값(1:PCM )

Number Channels

채널수(1:모노, 2:스테레오)

SampleRate

샘플링 수

BytePerSecond

초당 샘플 바이트

BytePerSample

샘플당 바이트

BitsPerSample

샘플당 비트수

Extraformatsize

부가정보 사이즈

extraformatdata

부가정보

 

 

 

 

 

Channel의 수에 따라서 저장되는 형태는

1채널일 때

2채널일 때

3채널일 때

숫자는 채널 번호이고, 채널의 수에 따라서 반복되면서 저장되어있다.

 

Extraforma은 존재하지 않을 수도 있는데, 그에 대한 판별은 Chunk Size를 확인했을 때 16보다 크게 되면 존재할 것이다.

 

 

 

 

4. data Chunk

 

 

이곳에 파형 데이터가 저장되어있다.

Chunk ID는 "data"이지만 "wavl"로 존재할 수도 있다.

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

5. 기타 Chunk

Chunk ID의 종류에는

    

등이 있다.

 

"fmt"와 "cue"는 3byte지만 ID의 크기는 4byte이기 때문에 뒤에 공백으로 채워진다.

위에서는 공백을 '_'로 표현하였다.

Chunk ID는 항상 소문자로 존재하지 않고, 대문자로 존재하는 경우도 있다.

 

'기타 > Wave' 카테고리의 다른 글

Wave 파일 분석  (0) 2012.11.02
주파수 생성  (0) 2012.08.16
옵티머스G 이어폰이 한달만에 왔음
내 귓구멍이 조그만지 잘빠짐 ㅠㅠ
음질은 아이폰 이어폰 음질이랑 별 차이를 못느끼겟으나
(내 귀가 싸구려라그럴지도...ㅜㅠ)
 
확실히 소음차단이 되어
작은 볼륨으로 음악을 감상 하거나 마이크를 이용해 통화를 할때
주변 소음에 방해받지 않을 것 같음!
이상 끝
 
 
 
 
 
 
 
 
        void timer_Tick(object sender, EventArgs e)
        {
            if (this.selectedFigure == null)
                return;

            using (Graphics g = this.panel_drawPaper.CreateGraphics())
            {
                Global global = Global.GetInstance();
                
                Point point = this.PointToScreen(this.selectedFigure.Location);
                point =new Point(point.X-2, point.Y-2);

                Rectangle rect = new Rectangle(point, new Size(global.DrawManager.DrawSize+5, global.DrawManager.DrawSize+5));

                ControlPaint.FillReversibleRectangle(rect, Color.Black);
            }
        }

 

ControlPaint Class의 FillReversibleRectangle 메서드를 이용하면 사각 영역의 해당 색상을 반전시키고,

DrawReversibleFrame 메서드는 사각 영역의 라인의 색상만 반전시킨다.

 

    public partial class Form1 : Form
    {
        public Form1()
        {
            InitializeComponent();
        }

        // The following three methods will draw a rectangle and allow 
        // the user to use the mouse to resize the rectangle.  If the 
        // rectangle intersects a control's client rectangle, the 
        // control's color will change.

        bool isDrag = false;
        Rectangle theRectangle = new Rectangle
            (new Point(0, 0), new Size(0, 0));
        Point startPoint;

        private void Form1_MouseDown(object sender,
            System.Windows.Forms.MouseEventArgs e)
        {

            // Set the isDrag variable to true and get the starting point 
            // by using the PointToScreen method to convert form 
            // coordinates to screen coordinates.
            if (e.Button == MouseButtons.Left)
            {
                isDrag = true;
            }

            Control control = (Control)sender;

            // Calculate the startPoint by using the PointToScreen 
            // method.
            startPoint = control.PointToScreen(new Point(e.X, e.Y));
        }

        private void Form1_MouseMove(object sender,
            System.Windows.Forms.MouseEventArgs e)
        {

            // If the mouse is being dragged, 
            // undraw and redraw the rectangle as the mouse moves.
            if (isDrag)

            // Hide the previous rectangle by calling the 
            // DrawReversibleFrame method with the same parameters.
            {
                ControlPaint.DrawReversibleFrame(theRectangle,
                    this.BackColor, FrameStyle.Dashed);

                // Calculate the endpoint and dimensions for the new 
                // rectangle, again using the PointToScreen method.
                Point endPoint = ((Control)sender).PointToScreen(new Point(e.X, e.Y));

                int width = endPoint.X - startPoint.X;
                int height = endPoint.Y - startPoint.Y;
                theRectangle = new Rectangle(startPoint.X,
                    startPoint.Y, width, height);

                // Draw the new rectangle by calling DrawReversibleFrame
                // again.  
                ControlPaint.DrawReversibleFrame(theRectangle,
                    this.BackColor, FrameStyle.Dashed);
            }
        }

        private void Form1_MouseUp(object sender,
            System.Windows.Forms.MouseEventArgs e)
        {

            // If the MouseUp event occurs, the user is not dragging.
            isDrag = false;

            // Draw the rectangle to be evaluated. Set a dashed frame style 
            // using the FrameStyle enumeration.
            ControlPaint.DrawReversibleFrame(theRectangle,
                this.BackColor, FrameStyle.Dashed);

            // Find out which controls intersect the rectangle and 
            // change their color. The method uses the RectangleToScreen  
            // method to convert the Control's client coordinates 
            // to screen coordinates.
            Rectangle controlRectangle;
            for (int i = 0; i < Controls.Count; i++)
            {
                controlRectangle = Controls[i].RectangleToScreen(Controls[i].ClientRectangle);
                if (controlRectangle.IntersectsWith(theRectangle))
                {
                    Controls[i].BackColor = Color.BurlyWood;
                }
            }

            // Reset the rectangle.
            theRectangle = new Rectangle(0, 0, 0, 0);
        }



    }

 

 

 

 

일단 부모창의 IsMdiContainer의 속성을 true로 변경해준다.

 

this.IsMdiContainer = true;

 

 

 

자식창을 생성 할 때 자식창의 MdiParent 속성에 부모 Form을 넣어준다.

  

                                                                                   Form form = new Form();
                                                                                   form.MdiParent = this;
                                                                                   form.Show();

 

 

 

MDI 정렬 시키는 방법은 부모의 LayoutMdi 메서드를 호출하면 된다.

 

this.LayoutMdi(MdiLayout.TileHorizontal);

 

 

 

 

 

멤버 이름

설명

Cascade

모든 MDI 자식 창은 MDI 부모 폼의 클라이언트 영역 내에서 계단식으로 배열됩니다.

TileHorizontal

모든 MDI 자식 창은 MDI 부모 폼의 클라이언트 영역 내에서 가로 바둑판식으로 배열됩니다.

TileVertical

모든 MDI 자식 창은 MDI 부모 폼의 클라이언트 영역 내에서 세로 바둑판식으로 배열됩니다.

ArrangeIcons

모든 MDI 자식 아이콘은 MDI 부모 폼의 클라이언트 영역 내에 정렬됩니다.

(표 1)MdiLayout Enum

*출처 : MSDN

void Document_PrintPage(object sender, System.Drawing.Printing.PrintPageEventArgs e) 
{ 
   int itar=0; 
   foreach (char c in this.richTextBox.Text) 
   { 
      if (c != '\n') 
      { 
         this.richTextBox.Select(itar, 1); 
         Point point = this.richTextBox.GetPositionFromCharIndex(itar); 
         e.Graphics.DrawString(c.ToString(), this.richTextBox.SelectionFont, new SolidBrush(this.richTextBox.SelectionColor), point); 
      } 
      itar++; 
   } 
}  

 

 n>=1개의 원소를 가진 집합이 주어졌을 때 이 집합의 모든 가능한 순열을 출력해보자. 예를들어 주어진 집합이 {a,b,c}라면 순열의 집합은

{(a,b,c),(a,c,b),(b,a,c),(b,c,a),(c,a,b),(c,b,a)이다. n개의 주어진 원소에 대해 n!개의 서로 다른 순열이 있다는 것은 쉽게 알 수 있다.

네개의 원소 (a,b,c,d)로 된 집합을 살펴보면 간단한 알고리즘을 얻을 수 있을 것이다. 해답은 다음과 같이 출력해 보면 얻을 수 있다.

 

 (1) a로 시작하는 (b,c,d)의 모든 순열

 (2) b로 시작하는 (a,c,d)의 모든 순열

 (3) c로 시작하는 (a,b,d)의 모든 순열

 (4) d로 시작하는 (a,b,c)의 모든 순열

 

 '~로 시작하는 ~의 모든 순열'이라는 표현이 바로 순환의 실마리이다. 이것은 n-1개의 원소에 동작하는 알고리즘이 있다면, n개의 원소를 가진 집합에 대한

문제도 해결 할 수 있다는 것을 의미한다. 이러한 생각으로 프로그램을 만들어 낼 수 있고, 이 함수는 Perm(a,0)이라는 식으로 호출된다.

 

 순환이 유용한 또 다른 예는, 알고리즘이 다루는 자료 구조가 순환적으로 정의되어 있는 경우이다.

 

C# 코드

namespace 순열
{
    class Program
    {
        static void Main(string[] args)
        {
            char[] datas = new char[] { 'a', 'b','c' };

            Perm(datas, 0);

            Console.ReadKey();
        }

        /// <summary>
        /// 순열을 출력한다.
        /// </summary>
        /// <param name="a"></param>
        /// <param name="k"></param>
        private static void Perm(char[] a, int k)
        {
            if (k == a.Length - 1)//순열을 출력
            {
                for (int i = 0; i < a.Length; i++)
                {
                    Console.Write("{0} ", a[i]);
                }
                Console.WriteLine();
            }
            else
            {
                for (int i = k; i < a.Length; i++)
                {
                    //a[k]와 a[i]를 교환
                    char temp = a[k];
                    a[k] = a[i];
                    a[i] = temp;

                    Perm(a, k + 1); //a[k+1],…,a[n-1]에 대한 모든 순열
                    //원래 상태로 되돌리기 위해 a[k]와 a[i]를 다시 교환
                    temp = a[k];
                    a[k] = a[i];
                    a[i] = temp;
                }
            }
        }
    }
}

 

순열.zip

 

참고 : C++ 자료구조론 - 이석호

'.Net > Algorithm' 카테고리의 다른 글

C# 이진탐색  (0) 2012.10.10
C# 선택정렬  (1) 2012.10.10

+ Recent posts