첨부 실행 코드는 나눔고딕코딩 폰트를 사용합니다.
유용한 소스 코드가 있으면 icodebroker@naver.com으로 보내주시면 감사합니다.
블로그 자료는 자유롭게 사용하세요.

728x90
반응형

■ 사면체(Tetrahedron) 사용하기

------------------------------------------------------------------------------------------------------------------------


TestProject.zip


MainWindow.xaml

 

 

<Window x:Class="TestProject.MainWindow"

    xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"

    xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"

    Width="800"

    Height="600"

    Title="사면체(Tetrahedron) 사용하기"

    FontFamily="나눔고딕코딩"

    FontSize="16"

    Loaded="Window_Loaded"

    KeyDown="Window_KeyDown">

    <Grid>

        <Grid.RowDefinitions>

            <RowDefinition Height="Auto" />

            <RowDefinition />

        </Grid.RowDefinitions>

        <Grid.ColumnDefinitions>

            <ColumnDefinition />

            <ColumnDefinition />

            <ColumnDefinition />

        </Grid.ColumnDefinitions>

        <Viewport3D Name="viewport3D" Grid.Row="1" Grid.RowSpan="2" Grid.Column="0" Grid.ColumnSpan="3" />

        <CheckBox Name="axisCheckBox" Grid.Row="0" Grid.Column="0"

            Margin="10"

            IsChecked="True"

            Content="축"

            Click="checkBox_Click" />

        <CheckBox Name="edgeCheckBox" Grid.Row="0" Grid.Column="1"

            Margin="10"

            IsChecked="True"

            Content="에지"

            Click="checkBox_Click" />

        <CheckBox Name="faceCheckBox" Grid.Row="0" Grid.Column="2"

            Margin="10"

            IsChecked="True"

            Content="면"

            Click="checkBox_Click"/>

    </Grid>

</Window>

 

 

MainWindow.xaml.cs

 

 

using System;

using System.Collections.Generic;

using System.Windows;

using System.Windows.Input;

using System.Windows.Media;

using System.Windows.Media.Media3D;

 

namespace TestProject

{

    /// <summary>

    /// 메인 윈도우

    /// </summary>

    public partial class MainWindow : Window

    {

        //////////////////////////////////////////////////////////////////////////////////////////////////// Field

        ////////////////////////////////////////////////////////////////////////////////////////// Private

 

        #region Field

 

        /// <summary>

        /// 모델 그룹

        /// </summary>

        private Model3DGroup modelGroup = new Model3DGroup();

 

        /// <summary>

        /// 조명 리스트

        /// </summary>

        private List<Light> lightList = new List<Light>();

 

        /// <summary>

        /// 면 모델

        /// </summary>

        private GeometryModel3D faceModel;

        

        /// <summary>

        /// 에지 모델

        /// </summary>

        private GeometryModel3D edgeModel;

        

        /// <summary>

        /// 축 모델

        /// </summary>

        private GeometryModel3D axisModel;

 

        /// <summary>

        /// 카메라

        /// </summary>

        private PerspectiveCamera camera;

 

        /// <summary>

        /// 카메라 파이

        /// </summary>

        private double cameraPhi = Math.PI / 6.0 - 4 * CAMERA_DELTA_PHI;

 

        /// <summary>

        /// 카메라 세타

        /// </summary>

        private double cameraTheta = Math.PI / 6.0 + 13 * CAMEREA_DELTA_THETA;

 

        /// <summary>

        /// 카메라 R

        /// </summary>

        private double cameraR = 2.0;

 

        /// <summary>

        /// 카메라 델타 파이

        /// </summary>

        private const double CAMERA_DELTA_PHI = 0.1;

 

        /// <summary>

        /// 카메라 델타 세타

        /// </summary>

        private const double CAMEREA_DELTA_THETA = 0.1;

 

        /// <summary>

        /// 카메라 델타 R

        /// </summary>

        private const double CAMERA_DELTA_R = 0.1;

 

        #endregion

 

        //////////////////////////////////////////////////////////////////////////////////////////////////// Constructor

        ////////////////////////////////////////////////////////////////////////////////////////// Public

 

        #region 생성자 - MainWindow()

 

        /// <summary>

        /// 생성자

        /// </summary>

        public MainWindow()

        {

            InitializeComponent();

        }

 

        #endregion

 

        //////////////////////////////////////////////////////////////////////////////////////////////////// Method

        ////////////////////////////////////////////////////////////////////////////////////////// Private

        //////////////////////////////////////////////////////////////////////////////// Event

 

        #region 윈도우 로드시 처리하기 - Window_Loaded(sender, e)

 

        /// <summary>

        /// 윈도우 로드시 처리하기

        /// </summary>

        /// <param name="sender">이벤트 발생자</param>

        /// <param name="e">이벤트 인자</param>

        private void Window_Loaded(object sender, RoutedEventArgs e)

        {

            this.camera = new PerspectiveCamera();

 

            this.camera.FieldOfView = 60;

 

            this.viewport3D.Camera = this.camera;

 

            SetCameraPosition();

 

            DefineLight();

 

            DefineModel(out this.faceModel, out this.edgeModel, out this.axisModel);

 

            this.modelGroup.Children.Add(this.faceModel);

            this.modelGroup.Children.Add(this.edgeModel);

            this.modelGroup.Children.Add(this.axisModel);

 

            ModelVisual3D modelVisual = new ModelVisual3D();

 

            modelVisual.Content = this.modelGroup;

 

            this.viewport3D.Children.Add(modelVisual);

        }

 

        #endregion

        #region 윈도우 키 DOWN 처리하기 - Window_KeyDown(sender, e)

 

        /// <summary>

        /// 윈도우 키 DOWN 처리하기

        /// </summary>

        /// <param name="sender">이벤트 발생자</param>

        /// <param name="e">이벤트 인자</param>

        private void Window_KeyDown(object sender, KeyEventArgs e)

        {

            switch(e.Key)

            {

                case Key.Up :

 

                    this.cameraPhi += CAMERA_DELTA_PHI;

 

                    if(this.cameraPhi > Math.PI / 2.0)

                    {

                        this.cameraPhi = Math.PI / 2.0;

                    }

 

                    break;

 

                case Key.Down :

 

                    this.cameraPhi -= CAMERA_DELTA_PHI;

 

                    if(this.cameraPhi < -Math.PI / 2.0)

                    {

                        this.cameraPhi = -Math.PI / 2.0;

                    }

 

                    break;

 

                case Key.Left :

 

                    this.cameraTheta += CAMEREA_DELTA_THETA;

 

                    break;

 

                case Key.Right :

 

                    this.cameraTheta -= CAMEREA_DELTA_THETA;

 

                    break;

 

                case Key.Add     :

                case Key.OemPlus :

 

                    this.cameraR -= CAMERA_DELTA_R;

 

                    if(this.cameraR < CAMERA_DELTA_R)

                    {

                        this.cameraR = CAMERA_DELTA_R;

                    }

 

                    break;

 

                case Key.Subtract :

                case Key.OemMinus :

 

                    this.cameraR += CAMERA_DELTA_R;

 

                    break;

            }

 

            SetCameraPosition();

        }

 

        #endregion

        #region 체크 박스 클릭시 처리하기 - checkBox_Click(sender, e)

 

        /// <summary>

        /// 체크 박스 클릭시 처리하기

        /// </summary>

        /// <param name="sender">이벤트 발생자</param>

        /// <param name="e">이벤트 인자</param>

        private void checkBox_Click(object sender, RoutedEventArgs e)

        {

            this.modelGroup.Children.Clear();

 

            foreach(Light light in this.lightList)

            {

                this.modelGroup.Children.Add(light);

            }

 

            if(this.axisCheckBox.IsChecked.Value)

            {

                this.modelGroup.Children.Add(this.axisModel);

            }

 

            if(this.faceCheckBox.IsChecked.Value)

            {

                this.modelGroup.Children.Add(this.faceModel);

            }

 

            if(this.edgeCheckBox.IsChecked.Value)

            {

                this.modelGroup.Children.Add(this.edgeModel);

            }

        }

 

        #endregion

        

        //////////////////////////////////////////////////////////////////////////////// Function

 

        #region 카메라 위치 설정하기 - SetCameraPosition()

 

        /// <summary>

        /// 카메라 위치 설정하기

        /// </summary>

        private void SetCameraPosition()

        {

            double y   = this.cameraR * Math.Sin(this.cameraPhi);

            double hyp = this.cameraR * Math.Cos(this.cameraPhi);

            double x   = hyp * Math.Cos(this.cameraTheta);

            double z   = hyp * Math.Sin(this.cameraTheta);

 

            this.camera.Position = new Point3D(x, y, z);

 

            this.camera.LookDirection = new Vector3D(-x, -y, -z);

 

            this.camera.UpDirection = new Vector3D(0, 1, 0);

        }

 

        #endregion

        #region 조명 정의하기 - DefineLight()

 

        /// <summary>

        /// 조명 정의하기

        /// </summary>

        private void DefineLight()

        {

            this.lightList.Add(new AmbientLight(Colors.Gray));

 

            this.lightList.Add(new DirectionalLight(Colors.Gray, new Vector3D(-1.0,  0.0, 0.5)));

            this.lightList.Add(new DirectionalLight(Colors.Gray, new Vector3D( 1.0, -1.0, 1.0)));

 

            foreach(Light light in this.lightList)

            {

                this.modelGroup.Children.Add(light);

            }

        }

 

        #endregion

        #region 스케일 벡터 구하기 - GetScaleVector(vector, length)

 

        /// <summary>

        /// 스케일 벡터 구하기

        /// </summary>

        /// <param name="vector">벡터</param>

        /// <param name="length">길이</param>

        /// <returns>스케일 벡터</returns>

        private Vector3D GetScaleVector(Vector3D vector, double length)

        {

            double scale = length / vector.Length;

 

            return new Vector3D

            (

                vector.X * scale,

                vector.Y * scale,

                vector.Z * scale

            );

        }

 

        #endregion

        #region 삼각형 추가하기 - AddTriangle(mesh, point1, point2, point3)

 

        /// <summary>

        /// 삼각형 추가하기

        /// </summary>

        /// <param name="mesh">메시</param>

        /// <param name="point1">포인트 1</param>

        /// <param name="point2">포인트 2</param>

        /// <param name="point3">포인트 3</param>

        private void AddTriangle(MeshGeometry3D mesh, Point3D point1, Point3D point2, Point3D point3)

        {

            int index = mesh.Positions.Count;

 

            mesh.Positions.Add(point1);

            mesh.Positions.Add(point2);

            mesh.Positions.Add(point3);

 

            mesh.TriangleIndices.Add(index++);

            mesh.TriangleIndices.Add(index++);

            mesh.TriangleIndices.Add(index  );

        }

 

        #endregion

        #region 세그먼트 추가하기 - AddSegment(mesh, point1, point2, upVector)

 

        /// <summary>

        /// 세그먼트 추가하기

        /// </summary>

        /// <param name="mesh">메시</param>

        /// <param name="point1">포인트 1</param>

        /// <param name="point2">포인트 2</param>

        /// <param name="upVector">UP 벡터</param>

        private void AddSegment(MeshGeometry3D mesh, Point3D point1, Point3D point2, Vector3D upVector)

        {

            const double THICKNESS = 0.01;

 

            Vector3D vector1 = point2 - point1;

 

            Vector3D scaleVector1 = GetScaleVector(upVector, THICKNESS / 2.0);

 

            Vector3D scaleVector2 = Vector3D.CrossProduct(vector1, scaleVector1);

 

            scaleVector2 = GetScaleVector(scaleVector2, THICKNESS / 2.0);

 

            Point3D p1pp = point1 + scaleVector1 + scaleVector2;

            Point3D p1mp = point1 - scaleVector1 + scaleVector2;

            Point3D p1pm = point1 + scaleVector1 - scaleVector2;

            Point3D p1mm = point1 - scaleVector1 - scaleVector2;

            Point3D p2pp = point2 + scaleVector1 + scaleVector2;

            Point3D p2mp = point2 - scaleVector1 + scaleVector2;

            Point3D p2pm = point2 + scaleVector1 - scaleVector2;

            Point3D p2mm = point2 - scaleVector1 - scaleVector2;

 

            AddTriangle(mesh, p1pp, p1mp, p2mp);

            AddTriangle(mesh, p1pp, p2mp, p2pp);

 

            AddTriangle(mesh, p1pp, p2pp, p2pm);

            AddTriangle(mesh, p1pp, p2pm, p1pm);

 

            AddTriangle(mesh, p1pm, p2pm, p2mm);

            AddTriangle(mesh, p1pm, p2mm, p1mm);

 

            AddTriangle(mesh, p1mm, p2mm, p2mp);

            AddTriangle(mesh, p1mm, p2mp, p1mp);

 

            AddTriangle(mesh, p1pp, p1pm, p1mm);

            AddTriangle(mesh, p1pp, p1mm, p1mp);

 

            AddTriangle(mesh, p2pp, p2mp, p2mm);

            AddTriangle(mesh, p2pp, p2mm, p2pm);

        }

 

        #endregion

        #region 사면체 포인트 배열 구하기 - GetTetrahedronPointArray()

 

        /// <summary>

        /// 사면체 포인트 배열 구하기

        /// </summary>

        /// <returns>사면체 포인트 배열</returns>

        private Point3D[] GetTetrahedronPointArray()

        {

            List<Point3D> pointList = new List<Point3D>();

 

            pointList.Add(new Point3D(0, Math.Sqrt(2.0 / 3.0), 0));

            pointList.Add(new Point3D(1 / Math.Sqrt(3.0), 0, 0));

            pointList.Add(new Point3D(-1.0 / (2.0 * Math.Sqrt(3)), 0, -0.5));

            pointList.Add(new Point3D(-1.0 / (2.0 * Math.Sqrt(3)), 0, 0.5));

 

            Vector3D offsetVector = new Vector3D(0, -1.0 / 2.0 / Math.Sqrt(3.0), 0);

 

            for(int i = 0; i < pointList.Count; i++)

            {

                pointList[i] = pointList[i] + offsetVector;

            }

 

            for(int i = 0; i < pointList.Count - 1; i++)

            {

                for(int j = i + 1; j < pointList.Count; j++)

                {

                    Vector3D vector = pointList[i] - pointList[j];

                }

            }

 

            return pointList.ToArray();

        }

 

        #endregion

        #region 모델 정의하기 - DefineModel(faceModel, edgeModel, axisModel)

 

        /// <summary>

        /// 모델 정의하기

        /// </summary>

        /// <param name="faceModel">면 모델</param>

        /// <param name="edgeModel">에지 모델</param>

        /// <param name="axisModel">축 모델</param>

        private void DefineModel(out GeometryModel3D faceModel, out GeometryModel3D edgeModel, out GeometryModel3D axisModel)

        {

            // 축 모델

            MeshGeometry3D axisMesh = new MeshGeometry3D();

 

            Point3D originPoint   = new Point3D(0   , 0   , 0   );

            Point3D maximumXPoint = new Point3D(0.75, 0   , 0   );

            Point3D maximumYPoint = new Point3D(0   , 0.75, 0   );

            Point3D maximumZPoint = new Point3D(0   , 0   , 0.75);

 

            AddSegment(axisMesh, originPoint, maximumXPoint, new Vector3D(0, 1, 0));

            AddSegment(axisMesh, originPoint, maximumZPoint, new Vector3D(0, 1, 0));

            AddSegment(axisMesh, originPoint, maximumYPoint, new Vector3D(1, 0, 0));

 

            SolidColorBrush axisBrush = Brushes.Red;

 

            DiffuseMaterial axisMaterial = new DiffuseMaterial(axisBrush);

 

            axisModel = new GeometryModel3D(axisMesh, axisMaterial);

 

 

            Point3D[] pointArray = GetTetrahedronPointArray();

 

 

            // 면 모델

            MeshGeometry3D faseMesh = new MeshGeometry3D();

 

            AddTriangle(faseMesh, pointArray[0], pointArray[1], pointArray[2]);

            AddTriangle(faseMesh, pointArray[0], pointArray[2], pointArray[3]);

            AddTriangle(faseMesh, pointArray[0], pointArray[3], pointArray[1]);

            AddTriangle(faseMesh, pointArray[3], pointArray[2], pointArray[1]);

 

            SolidColorBrush faceBrush = Brushes.LightBlue;

 

            DiffuseMaterial faceMaterial = new DiffuseMaterial(faceBrush);

 

            faceModel = new GeometryModel3D(faseMesh, faceMaterial);

 

            // 에지 모델

            MeshGeometry3D edgeMesh = new MeshGeometry3D();

 

            Vector3D upVector = new Vector3D(0, 1, 0);

 

            AddSegment(edgeMesh, pointArray[0], pointArray[1], upVector);

            AddSegment(edgeMesh, pointArray[0], pointArray[2], upVector);

            AddSegment(edgeMesh, pointArray[0], pointArray[3], upVector);

            AddSegment(edgeMesh, pointArray[1], pointArray[2], upVector);

            AddSegment(edgeMesh, pointArray[2], pointArray[3], upVector);

            AddSegment(edgeMesh, pointArray[3], pointArray[1], upVector);

 

            SolidColorBrush edgeBrush = Brushes.Blue;

 

            DiffuseMaterial edgeMaterial = new DiffuseMaterial(edgeBrush);

 

            edgeModel = new GeometryModel3D(edgeMesh, edgeMaterial);

        }

 

        #endregion

    }

}

 

------------------------------------------------------------------------------------------------------------------------

728x90
반응형
Posted by 사용자 icodebroker

댓글을 달아 주세요