Why MeshGeometry3D Plane is invisible on certain p

2019-03-06 06:02发布

问题:

Good day everyone, this is my first question here. So feel free to give me CC :)

About the project. I want to non-affine transfrom a flat polygonal plane without touchiung it´s Z-axis (0,0,0 0,1,0 1,0,0 1,1,0). I need to do that by positioning the 4 corner points of it. I achieved that by using the "Non-Affine Transforms in 2D by Charles Petzold (http://www.charlespetzold.com/blog/2007/08/250638.html).

Everything fine so far. And no dissapearing plane.

Because I need brushes/texture to expand over the edges of the plane. I decided to add triangles until I had 5x5 mesh of planes. (the whole geometry is still transformable by selecting the corner points of the first plane (it is the one in the middle.)

Sadly I am not allowed to post pictures yet.

https://i.imgur.com/oG3gKRD.png

The lightblue rectangle is the one with the selectable corners & the purple is the rest of it (for the pictures I inculded another plane (which is not connected to the big one, just to show that there is no crazy transformation effect) There is only a difference of 1 in the value (no matter what corner)

https://i.imgur.com/wSkywVk.png

It is not a problem with the camera as far as I could tell. Changing values on a lot of stuff like camera/near & farplanedistance. This positioning always results in invisible geometry (& it is not the only position leading to it, there are a few of them, but i am not able to see a connection) if I reduce the mesh to a 3x3 plane I have the same problem, only on other postions. The object is still there it is just not visible (I can still select the corner points and it will instantly visible again)

Does anyone know what can lead to that? Or does someone know how I can debug "errors" like that?

maybe is it the wrong approach for growing the transfomrable plane in general? If anyone has an idea let me know!

Setup for the geometry with both planes (two custom classes "scalingCanvas" and "CenterOnPoint" you can use a normal canvas with normal positoning)

<ResourceDictionary xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
                    xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
                    xmlns:local="clr-namespace:HtMatrix">
    <Style TargetType="local:HtProjektor">
        <Setter Property="Template">
            <Setter.Value>
                <ControlTemplate TargetType="local:HtProjektor">
                    <Grid Background="DarkOrange">
                        <Viewport3D Name="viewport3d"  Width="{TemplateBinding ActualWidth}" Height="{TemplateBinding ActualHeight}" >

                            <ModelVisual3D>
                                <ModelVisual3D.Content>
                                    <Model3DGroup>


                                        <GeometryModel3D>
                                            <GeometryModel3D.Geometry>


                                                <MeshGeometry3D x:Name="mesh"
                                                                Positions="0 0 0, 0 1 0, 1 0 0, 1 1 0,
                                                                0 1 0, 0 2 0, 1 1 0, 1 2 0,
                                                                0 -1 0, 0 0 0, 1 -1 0, 1 0 0,
                                                                1 1 0, 1 2 0, 2 1 0, 2 2 0,
                                                                1 0 0, 1 1 0, 2 0 0, 2 1 0,
                                                                1 -1 0, 1 0 0, 2 -1 0, 2 0 0,
                                                                -1 0 0, -1 1 0, 0 0 0, 0 1 0,
                                                                -1 1 0, -1 2 0, 0 1 0, 0 2 0,
                                                                -1 -1 0, -1 0 0, 0 -1 0, 0 0 0,

                                                                -2 2 0, -2 3 0, -1 2 0, -1 3 0,
                                                                -1 2 0, -1 3 0, 0 2 0, 0 3 0,
                                                                0 2 0, 0 3 0, 1 2 0, 1 3 0,
                                                                1 2 0, 1 3 0, 2 2 0, 2 3 0,
                                                                2 2 0, 2 3 0, 3 2 0, 3 3 0

                                                               -2 1 0, -2 2 0, -1 1 0, -1 2 0, 
                                                                2 1 0, 2 2 0, 3 1 0, 3 2 0,
                                                                -2 0 0, -2 1 0, -1 0 0, -1 1 0,
                                                                2 0 0, 2 1 0, 3 0 0, 3 1 0
                                                                -2 -1 0, -2 0 0, -1 -1 0, -1 0 0,                                                                
                                                                2 -1 0, 2 0 0, 3 -1 0, 3 0 0,

                                                                -2 -2 0, -2 -1 0, -1 -2 0, -1 -1 0,
                                                                -1 -2 0, -1 -1 0, 0 -2 0, 0 -1 0,
                                                                0 -2 0, 0 -1 0, 1 -2 0, 1 -1 0,
                                                                1 -2 0, 1 -1 0, 2 -2 0, 2 -1 0,
                                                                2 -2 0, 2 -1 0, 3 -2 0, 3 -1 0

                                                                "



                                                                TextureCoordinates="0 0, 0 1, 1 0, 1 1,
                                                                0 1, 0 2, 1 1, 1 2,
                                                                0 -1, 0 0, 1 -1, 1 0,
                                                                1 1, 1 2, 2 1, 2 2,
                                                                1 0, 1 1, 2 0, 2 1,
                                                                1 -1, 1 0, 2 -1, 2 0,
                                                                -1 0, -1 1, 0 0, 0 1,
                                                                -1 1, -1 2, 0 1, 0 2,
                                                                -1 -1, -1 0, 0 -1, 0 0,

                                                                -2 2, -2 3, -1 2, -1 3,
                                                                -1 2, -1 3, 0 2, 0 3,
                                                                0 2, 0 3, 1 2, 1 3,
                                                                1 2, 1 3, 2 2, 2 3,
                                                                2 2, 2 3, 3 2, 3 3

                                                                -2 1, -2 2, -1 1, -1 2, 
                                                                2 1, 2 2, 3 1, 3 2,
                                                                -2 0, -2 1, -1 0, -1 1,
                                                                2 0, 2 1, 3 0, 3 1,
                                                                -2 -1, -2 0, -1 -1, -1 0,
                                                                2 -1, 2 0, 3 -1, 3 0

                                                                -2 -2, -2 -1, -1 -2, -1 -1,
                                                                -1 -2, -1 -1, 0 -2, 0 -1,
                                                                0 -2, 0 -1, 1 -2, 1 -1,
                                                                1 -2, 1 -1, 2 -2, 2 -1,
                                                                2 -2, 2 -1, 3 -2, 3 -1
                                                                "

                                                                TriangleIndices="0 2 1, 1 2 3,
                                                                4 6 5, 5 6 7,
                                                                8 10 9, 9 10 11,
                                                                12 14 13, 13 14 15,
                                                                16 18 17, 17 18 19,
                                                                20 22 21, 21 22 23,
                                                                24 26 25, 25 26 27,
                                                                28 30 29, 29 30 31,
                                                                32 34 33, 33 34 35,

                                                                36 38 37, 37 38 39,
                                                                40 42 41, 41 42 43,
                                                                44 46 45, 45 46 47,
                                                                48 50 49, 49 50 51,
                                                                52 54 53, 53 54 55

                                                                56 58 57, 57 58 59,
                                                                60 62 61, 61 62 63,
                                                                64 66 65, 65 66 67,
                                                                68 70 69, 69 70 71,
                                                                72 74 73, 73 74 75,
                                                                76 78 77, 77 78 79,

                                                                80 82 81, 81 82 83,
                                                                84 86 85, 85 86 87,
                                                                88 90 89, 89 90 91,
                                                                92 94 93, 93 94 95,
                                                                96 98 97, 97 98 99

                                                                " />

                                            </GeometryModel3D.Geometry>


                                            <GeometryModel3D.Material>
                                                <DiffuseMaterial>
                                                    <DiffuseMaterial.Brush>
                                                        <VisualBrush>
                                                            <VisualBrush.Visual>



                                                                <local:ScalingCanvas  Background="Gray" Width="{TemplateBinding ActualWidth}" Height="{TemplateBinding ActualHeight}">

                                                                    <Grid Width="{TemplateBinding ActualWidth}" Height="{TemplateBinding ActualHeight}" ClipToBounds="True">


                                                                        <local:ScalingCanvas Width="{Binding RelativeSource={RelativeSource TemplatedParent}}" Height="{Binding RelativeSource={RelativeSource TemplatedParent}}" Background="PaleVioletRed" Opacity="0.5">
                                                                            <local:ScalingCanvas.RenderTransform>
                                                                                <ScaleTransform ScaleX="{Binding ScaleX, RelativeSource={RelativeSource TemplatedParent}}" ScaleY="{Binding ScaleY, RelativeSource={RelativeSource TemplatedParent}}"/>
                                                                            </local:ScalingCanvas.RenderTransform>
                                                                            <Rectangle Height="768" Width="1024"/>

                                                                            <Rectangle local:ScalingCanvas.Top="200" local:ScalingCanvas.Left="200"  Fill="Aqua" Width="100" Height="100" />
                                                                            <Rectangle local:CenterOnPoint.CenterPoint="100,100" Fill="Blue" Width="100" Height="100" Opacity="0.7"/>
                                                                            <Rectangle local:CenterOnPoint.CenterPoint="0,0" Fill="Yellow" Width="100" Height="100" Opacity="0.7"/>
                                                                            <Rectangle local:CenterOnPoint.CenterPoint="1024,0" Fill="Yellow" Width="100" Height="100" Opacity="0.7"/>
                                                                            <Rectangle local:CenterOnPoint.CenterPoint="0,768" Fill="Yellow" Width="100" Height="100" Opacity="0.7"/>
                                                                            <Rectangle local:CenterOnPoint.CenterPoint="1024,768" Fill="Yellow" Width="100" Height="100" Opacity="0.7"/>
                                                                            <Rectangle local:CenterOnPoint.CenterPoint="500, 0" Fill="Black" Height="100" Width="100"/>
                                                                            <Rectangle local:CenterOnPoint.CenterPoint="600, 768" Fill="Black" Height="100" Width="100"/>
                                                                            <Rectangle local:CenterOnPoint.CenterPoint="500, 868" Fill="Black" Height="100" Width="100"/>
                                                                            <Rectangle local:CenterOnPoint.CenterPoint="500, -100" Fill="Black" Height="100" Width="100"/>
                                                                            <Rectangle local:CenterOnPoint.CenterPoint="0,350" Fill="Black" Height="100" Width="100"/>
                                                                            <Rectangle local:CenterOnPoint.CenterPoint="1000,384" Fill="Black" Height="100" Width="100"/>
                                                                            <Rectangle local:CenterOnPoint.CenterPoint="512,384" Fill="YellowGreen" Height="153.6" Width="204.8" Opacity="0.5"/>

                                                                            <Image local:CenterOnPoint.CenterPoint="512,384" Source="IMG_4831.JPG" Width="100" Height="150" Stretch="Fill" />

                                                                        </local:ScalingCanvas>

                                                                    </Grid>

                                                                </local:ScalingCanvas>

                                                            </VisualBrush.Visual>
                                                        </VisualBrush>

                                                    </DiffuseMaterial.Brush>
                                                </DiffuseMaterial>
                                            </GeometryModel3D.Material>



                                            <GeometryModel3D.Transform >
                                                <Transform3DGroup>
                                                    <MatrixTransform3D x:Name="xform" />

                                                </Transform3DGroup>

                                            </GeometryModel3D.Transform>

                                        </GeometryModel3D>


                                    <GeometryModel3D>
                                        <GeometryModel3D.Geometry>


                                            <MeshGeometry3D x:Name="mesh1"
                                                            Positions="0 0 0, 0 1 0, 1 0 0, 1 1 0"
                                                            TextureCoordinates="0 0, 0 1, 1 0, 1 1" 
                                                            TriangleIndices="0 2 1, 2 3 1" />
                                        </GeometryModel3D.Geometry>


                                        <GeometryModel3D.Material>
                                            <DiffuseMaterial>
                                                <DiffuseMaterial.Brush>
                                                    <VisualBrush>
                                                        <VisualBrush.Visual>



                                                            <local:ScalingCanvas  Background="Gray" Width="{TemplateBinding ActualWidth}" Height="{TemplateBinding ActualHeight}">

                                                                <Grid Width="{TemplateBinding ActualWidth}" Height="{TemplateBinding ActualHeight}" ClipToBounds="True">


                                                                    <local:ScalingCanvas Width="{Binding RelativeSource={RelativeSource TemplatedParent}}" Height="{Binding RelativeSource={RelativeSource TemplatedParent}}" Background="AliceBlue" Opacity="0.5">
                                                                        <local:ScalingCanvas.RenderTransform>
                                                                            <ScaleTransform ScaleX="{Binding ScaleX, RelativeSource={RelativeSource TemplatedParent}}" ScaleY="{Binding ScaleY, RelativeSource={RelativeSource TemplatedParent}}"/>
                                                                        </local:ScalingCanvas.RenderTransform>
                                                                        <Rectangle Height="768" Width="1024"/>

                                                                        <Rectangle local:ScalingCanvas.Top="200" local:ScalingCanvas.Left="200"  Fill="Aqua" Width="100" Height="100" />
                                                                        <Rectangle local:CenterOnPoint.CenterPoint="100,100" Fill="Blue" Width="100" Height="100" Opacity="0.7"/>
                                                                        <Rectangle local:CenterOnPoint.CenterPoint="0,0" Fill="Yellow" Width="100" Height="100" Opacity="0.7"/>
                                                                        <Rectangle local:CenterOnPoint.CenterPoint="1024,0" Fill="Yellow" Width="100" Height="100" Opacity="0.7"/>
                                                                        <Rectangle local:CenterOnPoint.CenterPoint="0,768" Fill="Yellow" Width="100" Height="100" Opacity="0.7"/>
                                                                        <Rectangle local:CenterOnPoint.CenterPoint="1024,768" Fill="Yellow" Width="100" Height="100" Opacity="0.7"/>
                                                                        <Rectangle local:CenterOnPoint.CenterPoint="500, 0" Fill="Black" Height="100" Width="100"/>
                                                                        <Rectangle local:CenterOnPoint.CenterPoint="600, 768" Fill="Black" Height="100" Width="100"/>
                                                                        <Rectangle local:CenterOnPoint.CenterPoint="500, 868" Fill="Black" Height="100" Width="100"/>
                                                                        <Rectangle local:CenterOnPoint.CenterPoint="500, -100" Fill="Black" Height="100" Width="100"/>
                                                                        <Rectangle local:CenterOnPoint.CenterPoint="0,350" Fill="Black" Height="100" Width="100"/>
                                                                        <Rectangle local:CenterOnPoint.CenterPoint="1000,384" Fill="Black" Height="100" Width="100"/>
                                                                        <Rectangle local:CenterOnPoint.CenterPoint="512,384" Fill="YellowGreen" Height="153.6" Width="204.8" Opacity="0.5"/>

                                                                        <Image local:CenterOnPoint.CenterPoint="512,384" Source="IMG_4831.JPG" Width="100" Height="150" Stretch="Fill" />

                                                                    </local:ScalingCanvas>

                                                                </Grid>

                                                            </local:ScalingCanvas>

                                                        </VisualBrush.Visual>
                                                    </VisualBrush>

                                                </DiffuseMaterial.Brush>
                                            </DiffuseMaterial>
                                        </GeometryModel3D.Material>


                                        <GeometryModel3D.Transform >
                                            <Transform3DGroup>
                                                <MatrixTransform3D x:Name="xform2" />

                                            </Transform3DGroup>

                                        </GeometryModel3D.Transform>

                                    </GeometryModel3D>

                                        <!--Light source.--> 

                                        <AmbientLight Color="White" />
                                    </Model3DGroup>
                                </ModelVisual3D.Content>
                            </ModelVisual3D>

                            <!-- Camera. -->
                            <Viewport3D.Camera>
                                <OrthographicCamera Position="0.5 0.5 1"
                                                    LookDirection="0 0 -1"
                                                    UpDirection="0 1 0"
                                                    Width="1"

                                                   />

                            </Viewport3D.Camera>

                        </Viewport3D>
                    </Grid>
                </ControlTemplate>
            </Setter.Value>
        </Setter>
    </Style>
</ResourceDictionary>

The Projektor class will be posted as an answer because the limitation of character. If you need anything to clear things up just let me know! & is this question to big in general? I welcome cunstructive critic! :)

回答1:

The Projektor Class with the calculations! Is it possible to connect a comment to the main qestion?

HtProjektor.cs

        using System;
    using System.ComponentModel;
    using System.Diagnostics;
    using System.Windows;
    using System.Windows.Controls;
    using System.Windows.Input;
    using System.Windows.Media;
    using System.Windows.Media.Media3D;

    namespace HtMatrix
    {
        public class HtProjektor : Control
        {



            /// <summary>
            /// Breite in mm
            /// </summary>
            public int Breite
            {
                get { return (int)GetValue(BreiteProperty); }
                set { SetValue(BreiteProperty, value); }
            }

            /// <summary>
            /// The <see cref="Breite"/> DependencyProperty.
            /// </summary>
            public static readonly DependencyProperty BreiteProperty = DependencyProperty.Register("Breite", typeof(int), typeof(HtProjektor), new PropertyMetadata(1024, _DisplayScaleChanged));


            /// Höhe in mm

            public int Hoehe
            {
                get { return (int)GetValue(HoeheProperty); }
                set { SetValue(HoeheProperty, value); }
            }


            /// The <see cref="Hoehe"/> DependencyProperty.

            public static readonly DependencyProperty HoeheProperty = DependencyProperty.Register("Hoehe", typeof(int), typeof(HtProjektor), new PropertyMetadata(768, _DisplayScaleChanged));

            private static void _DisplayScaleChanged(DependencyObject dependencyObject, DependencyPropertyChangedEventArgs dependencyPropertyChangedEventArgs)

            {
                if (dependencyObject is HtProjektor projektor)
                {
                    projektor.ScaleX = projektor.ActualWidth / projektor.Breite;
                    projektor.ScaleY = projektor.ActualHeight / projektor.Hoehe;

                }
            }


            /// Skalierung X

            public double ScaleX
            {
                get { return (double)GetValue(ScaleXProperty); }
                set { SetValue(ScaleXProperty, value); }
            }


            /// The <see cref="ScaleX"/> DependencyProperty.

            public static readonly DependencyProperty ScaleXProperty = DependencyProperty.Register("ScaleX", typeof(double), typeof(HtProjektor), new PropertyMetadata(0.0));


            /// Skalierung Y

            public double ScaleY
            {
                get { return (double)GetValue(ScaleYProperty); }
                set { SetValue(ScaleYProperty, value); }
            }

            /// The <see cref="ScaleY"/> DependencyProperty.

            public static readonly DependencyProperty ScaleYProperty = DependencyProperty.Register("ScaleY", typeof(double), typeof(HtProjektor), new PropertyMetadata(0.0));

            /// The Top Left point

            public Point CurrentMousePosition
            {
                get { return (Point)GetValue(CurrentMousePositionProperty); }
                set { SetValue(CurrentMousePositionProperty, value); }
            }


            /// The <see cref="TopLeftPoint"/> DependencyProperty.

            public static readonly DependencyProperty CurrentMousePositionProperty = DependencyProperty.Register("CurrentMousePosition", typeof(Point), typeof(HtProjektor));


            /// The Top Left point

            public Point TopLeftPoint
            {
                get { return (Point)GetValue(TopLeftPointProperty); }
                set { SetValue(TopLeftPointProperty, value); }
            }


            /// The <see cref="TopLeftPoint"/> DependencyProperty.

            public static readonly DependencyProperty TopLeftPointProperty = DependencyProperty.Register("TopLeftPoint", typeof(Point), typeof(HtProjektor), new PropertyMetadata(_Coordinate_Changed));


            /// The Top Right point

            public Point TopRightPoint
            {
                get { return (Point)GetValue(TopRightPointProperty); }
                set { SetValue(TopRightPointProperty, value); }
            }


            /// The <see cref="TopRightPoint"/> DependencyProperty.

            public static readonly DependencyProperty TopRightPointProperty = DependencyProperty.Register("TopRightPoint", typeof(Point), typeof(HtProjektor), new PropertyMetadata(_Coordinate_Changed));


            /// The Bottom Left point

            public Point BottomLeftPoint
            {
                get { return (Point)GetValue(BottomLeftPointProperty); }
                set { SetValue(BottomLeftPointProperty, value); }
            }


            /// The <see cref="BottomLeftPoint"/> DependencyProperty.

            public static readonly DependencyProperty BottomLeftPointProperty = DependencyProperty.Register("BottomLeftPoint", typeof(Point), typeof(HtProjektor), new PropertyMetadata(_Coordinate_Changed));


            /// The Bottom Right point

            public Point BottomRightPoint
            {
                get { return (Point)GetValue(BottomRightPointProperty); }
                set { SetValue(BottomRightPointProperty, value); }
            }


            /// The <see cref="BottomRightPoint"/> DependencyProperty.

            public static readonly DependencyProperty BottomRightPointProperty = DependencyProperty.Register("BottomRightPoint", typeof(Point), typeof(HtProjektor), new PropertyMetadata(_Coordinate_Changed));

            private static void _Coordinate_Changed(DependencyObject dependencyObject, DependencyPropertyChangedEventArgs dependencyPropertyChangedEventArgs)
            {
                if (dependencyObject is HtProjektor projektor)
                {
                    Point pointTl = projektor.Simple3Dto2D(projektor._Viewport3D, projektor.pointsTransformed[1]);
                    Point pointTr = projektor.Simple3Dto2D(projektor._Viewport3D, projektor.pointsTransformed[3]);
                    Point pointBl = projektor.Simple3Dto2D(projektor._Viewport3D, projektor.pointsTransformed[0]);
                    Point pointBr = projektor.Simple3Dto2D(projektor._Viewport3D, projektor.pointsTransformed[2]);
                    projektor.TLX = (int)pointTl.X;
                    projektor.TLY = (int)pointTl.Y;

                    projektor.TRX = (int)pointTr.X;
                    projektor.TRY = (int)pointTr.Y;

                    projektor.BLX = (int)pointBl.X;
                    projektor.BLY = (int)pointBl.Y;

                    projektor.BRX = (int)pointBr.X;
                    projektor.BRY = (int)pointBr.Y;
                }
            }

            /// <summary>
            /// The top left x coordinate
            /// </summary>
            public int TLX
            {
                get { return (int)GetValue(TLXProperty); }
                set { SetValue(TLXProperty, value); }
            }

            /// <summary>
            /// The <see cref="TLX"/> DependencyProperty.
            /// </summary>
            public static readonly DependencyProperty TLXProperty = DependencyProperty.Register("TLX", typeof(int), typeof(HtProjektor), new PropertyMetadata(0, _Pixel_Tl_CoordinateChanged));

            /// <summary>
            /// The top left y coordinate
            /// </summary>
            public int TLY
            {
                get { return (int)GetValue(TLYProperty); }
                set { SetValue(TLYProperty, value); }
            }

            /// <summary>
            /// The <see cref="TLY"/> DependencyProperty.
            /// </summary>
            public static readonly DependencyProperty TLYProperty = DependencyProperty.Register("TLY", typeof(int), typeof(HtProjektor), new PropertyMetadata(0, _Pixel_Tl_CoordinateChanged));

            private static void _Pixel_Tl_CoordinateChanged(DependencyObject dependencyObject, DependencyPropertyChangedEventArgs dependencyPropertyChangedEventArgs)
            {
                if (dependencyObject is HtProjektor projektor)
                {
                    projektor.pointsTransformed[1] = projektor.Simple2Dto3D(projektor._Viewport3D, new Point(projektor.TLX, projektor.TLY)); //links oben
                    projektor._MatrixTransform3D.Matrix = projektor.CalculateNonAffineTransform(projektor.pointsTransformed);
                    projektor._MatrixTransform3D02.Matrix = projektor.CalculateNonAffineTransform(projektor.pointsTransformed);


                }
            }

            /// <summary>
            /// The top right X coordinate
            /// </summary>
            public int TRX
            {
                get { return (int)GetValue(TRXProperty); }
                set { SetValue(TRXProperty, value); }
            }

            /// <summary>
            /// The <see cref="TRX"/> DependencyProperty.
            /// </summary>
            public static readonly DependencyProperty TRXProperty = DependencyProperty.Register("TRX", typeof(int), typeof(HtProjektor), new PropertyMetadata(0, _Pixel_Tr_CoordinateChanged));

            /// <summary>
            /// The top right y coordinate
            /// </summary>
            public int TRY
            {
                get { return (int)GetValue(TRYProperty); }
                set { SetValue(TRYProperty, value); }
            }

            /// <summary>
            /// The <see cref="TRY"/> DependencyProperty.
            /// </summary>
            public static readonly DependencyProperty TRYProperty = DependencyProperty.Register("TRY", typeof(int), typeof(HtProjektor), new PropertyMetadata(0, _Pixel_Tr_CoordinateChanged));

            private static void _Pixel_Tr_CoordinateChanged(DependencyObject dependencyObject, DependencyPropertyChangedEventArgs dependencyPropertyChangedEventArgs)
            {
                if (dependencyObject is HtProjektor projektor)
                {
                    projektor.pointsTransformed[3] = projektor.Simple2Dto3D(projektor._Viewport3D, new Point(projektor.TRX, projektor.TRY)); //rechts oben
                    projektor._MatrixTransform3D.Matrix = projektor.CalculateNonAffineTransform(projektor.pointsTransformed);
                    projektor._MatrixTransform3D02.Matrix = projektor.CalculateNonAffineTransform(projektor.pointsTransformed);


                }
            }

            /// <summary>
            /// The bottom left x coordinate
            /// </summary>
            public int BLX
            {
                get { return (int)GetValue(BLXProperty); }
                set { SetValue(BLXProperty, value); }
            }

            /// <summary>
            /// The <see cref="BLX"/> DependencyProperty.
            /// </summary>
            public static readonly DependencyProperty BLXProperty = DependencyProperty.Register("BLX", typeof(int), typeof(HtProjektor), new PropertyMetadata(0, _Pixel_Bl_CoordinateChanged));

            /// <summary>
            /// The bottom left y coordinate
            /// </summary>
            public int BLY
            {
                get { return (int)GetValue(BLYProperty); }
                set { SetValue(BLYProperty, value); }
            }

            /// <summary>
            /// The <see cref="BLY"/> DependencyProperty.
            /// </summary>
            public static readonly DependencyProperty BLYProperty = DependencyProperty.Register("BLY", typeof(int), typeof(HtProjektor), new PropertyMetadata(0, _Pixel_Bl_CoordinateChanged));

            private static void _Pixel_Bl_CoordinateChanged(DependencyObject dependencyObject, DependencyPropertyChangedEventArgs dependencyPropertyChangedEventArgs)
            {
                if (dependencyObject is HtProjektor projektor)
                {
                    projektor.pointsTransformed[0] = projektor.Simple2Dto3D(projektor._Viewport3D, new Point(projektor.BLX, projektor.BLY)); //links unten
                    projektor._MatrixTransform3D.Matrix = projektor.CalculateNonAffineTransform(projektor.pointsTransformed);
                    projektor._MatrixTransform3D02.Matrix = projektor.CalculateNonAffineTransform(projektor.pointsTransformed);

                }
            }

            /// <summary>
            /// The bottom right x coordinate
            /// </summary>
            public int BRX
            {
                get { return (int)GetValue(BRXProperty); }
                set { SetValue(BRXProperty, value); }
            }

            /// <summary>
            /// The <see cref="BRX"/> DependencyProperty.
            /// </summary>
            public static readonly DependencyProperty BRXProperty = DependencyProperty.Register("BRX", typeof(int), typeof(HtProjektor), new PropertyMetadata(0, _Pixel_Br_CoordinateChanged));

            /// <summary>
            /// The bottom right y coordinate
            /// </summary>
            public int BRY
            {
                get { return (int)GetValue(BRYProperty); }
                set { SetValue(BRYProperty, value); }
            }

            /// <summary>
            /// The <see cref="BRY"/> DependencyProperty.
            /// </summary>
            public static readonly DependencyProperty BRYProperty = DependencyProperty.Register("BRY", typeof(int), typeof(HtProjektor), new PropertyMetadata(0, _Pixel_Br_CoordinateChanged));

            private static void _Pixel_Br_CoordinateChanged(DependencyObject dependencyObject, DependencyPropertyChangedEventArgs dependencyPropertyChangedEventArgs)
            {
                if (dependencyObject is HtProjektor projektor)
                {              
                    projektor.pointsTransformed[2] = projektor.Simple2Dto3D(projektor._Viewport3D, new Point(projektor.BRX, projektor.BRY)); //rechts unten
                    projektor._MatrixTransform3D.Matrix = projektor.CalculateNonAffineTransform(projektor.pointsTransformed);
                    projektor._MatrixTransform3D02.Matrix = projektor.CalculateNonAffineTransform(projektor.pointsTransformed);


                }
            }

            #endregion


            // ##########################################################################################
            // Private Properties
            // ##########################################################################################

            private MeshGeometry3D _MeshGeometry3D;
           // private MeshGeometry3D _MeshGeometry3D02;
            private MatrixTransform3D _MatrixTransform3D;
            private MatrixTransform3D _MatrixTransform3D02;


            private Viewport3D _Viewport3D;

            #endregion

            // ##############################################################################################################################
            // Konstruktor
            // ##############################################################################################################################

            #region Konstruktor

            public HtProjektor()
            {
                DefaultStyleKey = typeof(HtProjektor);
                if (!DesignerProperties.GetIsInDesignMode(this))
                {
                    Loaded += _OnLoaded;
                }
            }

            private void _OnLoaded(object sender, RoutedEventArgs routedEventArgs)
            {
                _MeshGeometry3D = GetTemplateChild("mesh") as MeshGeometry3D;
               // _MeshGeometry3D02 = GetTemplateChild("mesh1") as MeshGeometry3D;
                _MatrixTransform3D = GetTemplateChild("xform") as MatrixTransform3D;
                _MatrixTransform3D02 = GetTemplateChild("xform2") as MatrixTransform3D;




                _Viewport3D = GetTemplateChild("viewport3d") as Viewport3D;

                for (int i = 0; i < 4; i++)
                    pointsTransformed[i] = _MatrixTransform3D.Matrix.Transform(_MeshGeometry3D.Positions[i]);

                for (int i = 0; i < 4; i++)
                    pointsTransformed[i] = _MatrixTransform3D02.Matrix.Transform(_MeshGeometry3D.Positions[i]);




                TopLeftPoint = new Point(pointsTransformed[1].X, pointsTransformed[1].Y);
                TopRightPoint = new Point(pointsTransformed[3].X, pointsTransformed[3].Y);
                BottomLeftPoint = new Point(pointsTransformed[0].X, pointsTransformed[0].Y);
                BottomRightPoint = new Point(pointsTransformed[2].X, pointsTransformed[2].Y);

                ScaleX = ActualWidth / Breite;
                ScaleY = ActualHeight / Hoehe;
            }

            protected override Size ArrangeOverride(Size arrangeBounds)
            {
                FixToBounds(arrangeBounds.Width, arrangeBounds.Height);
                return base.ArrangeOverride(arrangeBounds);                  
            }

            #endregion

            bool isDragging;
            int indexDragging;
            Point3D[] pointsTransformed = new Point3D[4];

            protected override void OnMouseLeftButtonDown(MouseButtonEventArgs args)
            {
                Point pt = args.GetPosition(_Viewport3D);

                // Obtain the Visual3D objects under the mouse pointer.
                HitTestResult result = VisualTreeHelper.HitTest(_Viewport3D, pt);

                // Cast result parameter to RayMeshGeometry3DHitTestResult.
                RayMeshGeometry3DHitTestResult resultMesh = result as RayMeshGeometry3DHitTestResult;

                // This should not happen, but play it safe anyway.
                if (resultMesh == null)
                    return;

                // Obtain clicked ModelVisual3D.
                ModelVisual3D vis = resultMesh.VisualHit as ModelVisual3D;

                // This should not happen, but play it safe anyway.
                if (vis == null)
                    return;

                // Determine which vertex the mouse is closest to.
                if (resultMesh.VertexWeight1 < resultMesh.VertexWeight2)
                {
                    if (resultMesh.VertexWeight2 < resultMesh.VertexWeight3)
                        indexDragging = resultMesh.VertexIndex3;
                    else
                        indexDragging = resultMesh.VertexIndex2;
                }
                else if (resultMesh.VertexWeight3 > resultMesh.VertexWeight1)
                    indexDragging = resultMesh.VertexIndex3;
                else
                    indexDragging = resultMesh.VertexIndex1;

                // Get current transformed points.
                for (int i = 0; i < 4; i++)
                    pointsTransformed[i] = _MatrixTransform3D.Matrix.Transform(_MeshGeometry3D.Positions[i]);

                // Obtain new transform and commence dragging operation.
                pointsTransformed[indexDragging] = Simple2Dto3D(_Viewport3D, pt);
                _MatrixTransform3D.Matrix = CalculateNonAffineTransform(pointsTransformed);

                _MatrixTransform3D02.Matrix = CalculateNonAffineTransform(pointsTransformed);


                isDragging = true;
                CaptureMouse();
                args.Handled = true;
            }

            protected override void OnMouseMove(MouseEventArgs args)
            {
                base.OnMouseMove(args);

                if (isDragging)
                {
                    Point ptMouse = args.GetPosition(_Viewport3D);
                    //if (ptMouse.Y <= 0.0)
                    //    ptMouse.Y = 0.0;
                    //else if (ptMouse.X <= 0.0)
                    //    ptMouse.X = 0.0;
                    //if (ptMouse.Y >= ActualHeight)
                    //    ptMouse.Y = ActualHeight;
                    //else if (ptMouse.X >= ActualWidth)
                    //    ptMouse.X = ActualWidth;

                    pointsTransformed[indexDragging] = Simple2Dto3D(_Viewport3D, ptMouse);
                    _MatrixTransform3D.Matrix = CalculateNonAffineTransform(pointsTransformed);

                    _MatrixTransform3D02.Matrix = CalculateNonAffineTransform(pointsTransformed);


                    args.Handled = true;

                    TopLeftPoint = new Point(pointsTransformed[1].X, pointsTransformed[1].Y);
                    TopRightPoint = new Point(pointsTransformed[3].X, pointsTransformed[3].Y);
                    BottomLeftPoint = new Point(pointsTransformed[0].X, pointsTransformed[0].Y);
                    BottomRightPoint = new Point(pointsTransformed[2].X, pointsTransformed[2].Y);
                }

                CurrentMousePosition = args.GetPosition(_Viewport3D);
            }

            protected override void OnMouseLeftButtonUp(MouseButtonEventArgs args)
            {
                base.OnMouseUp(args);

                if (isDragging)
                {
                    isDragging = false;
                    ReleaseMouseCapture();
                    args.Handled = true;
                }
            }

            private void FixToBounds(double width, double height)
            {
                if(_Viewport3D?.Camera == null)return;

                pointsTransformed[0] = Simple2Dto3D(_Viewport3D, new Point(0.0, height)); //links unten
                pointsTransformed[1] = Simple2Dto3D(_Viewport3D, new Point(0.0, 0.0)); //links oben
                pointsTransformed[2] = Simple2Dto3D(_Viewport3D, new Point(width, height)); //rechts unten
                pointsTransformed[3] = Simple2Dto3D(_Viewport3D, new Point(width, 0.0)); //rechts oben

                _MatrixTransform3D.Matrix = CalculateNonAffineTransform(pointsTransformed);

                _MatrixTransform3D02.Matrix = CalculateNonAffineTransform(pointsTransformed);







            #region Private Methods

            // The input array of points describes a 2D rectangle
            //  (with Z assumed to be zero) in the order
            //  lower-left, upper-left, lower-right, upper-right.
            // The returned transform maps the points (0, 0, 0),
            //  (0, 1, 0), (1, 0, 0), and (1, 1, 0) to these points.
            Matrix3D CalculateNonAffineTransform(Point3D[] points)
            {
                // Affine transform
                // ----------------
                // This matrix maps (0, 0) --> (x0, y0)
                //                  (0, 1) --> (x1, y1)
                //                  (1, 0) --> (x2, y2)
                //                  (1, 1) --> (x2 + x1 + x0, y2 + y1 + y0)
                Matrix3D A = new Matrix3D();
                A.M11 = points[2].X - points[0].X;
                A.M12 = points[2].Y - points[0].Y;
                A.M21 = points[1].X - points[0].X;
                A.M22 = points[1].Y - points[0].Y;
                A.OffsetX = points[0].X;
                A.OffsetY = points[0].Y;

                // Calculate point (a, b) that get mapped by the affine transform to (x3, y3)
                double den = A.M11 * A.M22 - A.M12 * A.M21;
                double a = (A.M22 * points[3].X - A.M21 * points[3].Y + 
                            A.M21 * A.OffsetY - A.M22 * A.OffsetX) / den;

                double b = (A.M11 * points[3].Y - A.M12 * points[3].X + 
                            A.M12 * A.OffsetX - A.M11 * A.OffsetY) / den;

                // Non-affine transform
                // --------------------
                // This matrix maps (0, 0) --> (0, 0)
                //                  (0, 1) --> (0, 1)
                //                  (1, 0) --> (1, 0)
                //                  (1, 1) --> (a, b)

                Matrix3D B = new Matrix3D();
                B.M11 = a / (a + b - 1);
                B.M22 = b / (a + b - 1);
                B.M14 = B.M11 - 1;
                B.M24 = B.M22 - 1;

                return B * A;
            }

            // The following two methods only work with OrthographicCamera,
            // with LookDirection of (0, 0, -1) and UpDirection of (0, 1, 0).
            // More advanced conversion routines can be found in the 
            // Petzold.Media3D library.

            // Converts a 2D point in device-independent coordinates relative 
            //  to Viewport3D to 3D space.
            Point3D Simple2Dto3D(Viewport3D vp, Point pt)
            {
                OrthographicCamera cam = CheckRestrictions(vp);
                double scale = cam.Width / vp.ActualWidth;
                double x = scale * (pt.X - vp.ActualWidth / 2) + cam.Position.X;
                double y = scale * (vp.ActualHeight / 2 - pt.Y) + cam.Position.Y;

                return new Point3D(x, y, 0);
            }

            // Converts a 3D point to 2D in device-independent coordinates
            //  relative to Viewport3D.
            Point Simple3Dto2D(Viewport3D vp, Point3D point)
            {
                OrthographicCamera cam = CheckRestrictions(vp);
                double scale = vp.ActualWidth / cam.Width;
              //  double scale2 = vp.ActualHeight / cam.Width;
                double x = vp.ActualWidth / 2 + scale * (point.X - cam.Position.X);
                double y = vp.ActualHeight / 2 - scale * (point.Y - cam.Position.Y);
                return new Point(x, y);
            }

            OrthographicCamera CheckRestrictions(Viewport3D vp)
            {
                OrthographicCamera cam = vp.Camera as OrthographicCamera;

                if (cam == null)
                    throw new ArgumentException("Camera must be OrthographicCamera");

                if (cam.LookDirection != new Vector3D(0, 0, -1))
                    throw new ArgumentException("Camera LookDirection must be (0, 0, -1)");

                if (cam.UpDirection != new Vector3D(0, 1, 0))
                    throw new ArgumentException("Camera UpDirection must be (0, 1, 0)");

                return cam;
            }

            #endregion

        }
    }