private void RecreateControlPointNumbers()
        {
            if (_controlPoints == null)
            {
                return;
            }

            OverlayCanvas.Children.Clear();

            for (int i = 0; i < _controlPoints.Count; i++)
            {
                TextBlock textBlock = new TextBlock();
                textBlock.FontSize   = 10;
                textBlock.Foreground = Brushes.Red;
                textBlock.FontWeight = FontWeights.Bold;
                textBlock.Text       = i.ToString();

                // Calculate the 2D position of the 3D control point
                Point point2D = Camera1.Point3DTo2D(_controlPoints[i]);

                Canvas.SetLeft(textBlock, point2D.X + 10);
                Canvas.SetTop(textBlock, point2D.Y - 7);

                OverlayCanvas.Children.Add(textBlock);
            }
        }
Exemple #2
0
        private void UpdateOverlayCanvasElements()
        {
            if (!this.IsLoaded)
            {
                return;
            }

            // Start with right top back edge of the Box
            //var position3D = GoldBoxVisual3D.CenterPosition + new Vector3D(-GoldBoxVisual3D.Size.X / 2, GoldBoxVisual3D.Size.Y / 2, GoldBoxVisual3D.Size.Z / 2);
            var position3D = GoldBoxVisual3D.CenterPosition + new Vector3D(0, GoldBoxVisual3D.Size.Y / 2, 0);

            if (_overlayBrushHeight < 0.001)
            {
                OverlayInfoTextBlock.Measure(new Size(double.PositiveInfinity, double.PositiveInfinity));
                _overlayBrushHeight = OverlayInfoTextBlock.DesiredSize.Height + OverlayInfoBorder.BorderThickness.Bottom + OverlayInfoBorder.BorderThickness.Top;
            }

            var pos1 = Camera1.Point3DTo2D(position3D);
            var pos2 = pos1 + new Vector(30, -20);

            OverlayLine.X1 = pos1.X;
            OverlayLine.Y1 = pos1.Y;

            OverlayLine.X2 = pos2.X;
            OverlayLine.Y2 = pos2.Y;

            Canvas.SetLeft(OverlayInfoBorder, pos2.X);
            Canvas.SetTop(OverlayInfoBorder, pos2.Y - _overlayBrushHeight / 2);
        }
Exemple #3
0
        private void ViewportBorder_MouseLeftButtonUp(object sender, MouseButtonEventArgs e)
        {
            if (_currentObjectCreationState != ObjectCreationStates.SelectBaseSize)
            {
                return;
            }


            double boxWidth = _selectedObjectScaleTransform.ScaleX;
            double boxDepth = _selectedObjectScaleTransform.ScaleZ;

            if (boxWidth * boxDepth < 1)
            {
                // Box too small - user probably only clicked with the mouse and did not make a drag to define the base size
                // Remove the added object
                _currentObjectCreationState = ObjectCreationStates.SelectStartPoint;
                ObjectsVisual.Children.Remove(_selectedModelVisual3D);

                return;
            }


            _selectHeightStartMousePosition = e.GetPosition(MainViewport);

            // Now we will measure how much is one pixel on screen in 3D
            // This will be used in setting the height of the object with moving the mouse up
            Point3D p1 = _lastIntersectionPoint;
            Point3D p2 = new Point3D(p1.X, p1.Y + 1, p1.Z);

            Point p1_screen = Camera1.Point3DTo2D(p1);
            Point p2_screen = Camera1.Point3DTo2D(p2);


            // We have the base object - now define the height
            _screenTo3DFactor = 1.0 / Math.Abs(p2_screen.Y - p1_screen.Y);

            if (CreateBoxButton.IsChecked ?? false)
            {
                _currentObjectCreationState = ObjectCreationStates.SelectHeight;
            }
            else
            {
                _currentObjectCreationState = ObjectCreationStates.SelectStartPoint;
            }
        }
        private void UpdateControlPointNumbers()
        {
            if (OverlayCanvas.Children.Count == 0)
            {
                return;
            }

            for (int i = 0; i < OverlayCanvas.Children.Count; i++)
            {
                TextBlock textBlock = (TextBlock)OverlayCanvas.Children[i];

                // Calculate the 2D position of the 3D control point
                Point point2D = Camera1.Point3DTo2D(_controlPoints[i]);

                Canvas.SetLeft(textBlock, point2D.X + 10);
                Canvas.SetTop(textBlock, point2D.Y - 7);
            }
        }
        private void SelectionOverlayCanvasOnMouseLeftButtonDown(object sender, MouseButtonEventArgs e)
        {
            // We do not start selecting immediately when mouse is down
            // but wait until mouse is moved for a few pixels.
            // This prevents interfering with handling mouse click events
            _isSelectStarting = true;

            Point position = e.GetPosition(SelectionOverlayCanvas);

            _startSelectionPosition = position;

            // Calculate screen positions for all spheres so that we can do a quick check if a sphere is inside selection rectangle
            foreach (var positionData in _allSpheresData)
            {
                positionData.ScreenPosition = Camera1.Point3DTo2D(positionData.Position);
            }

            e.Handled = true;
        }
        private void UpdateDescriptionConnectionLine()
        {
            var sampleData = _samplesData[_currentSampleIndex];

            Point3D targetObjectPosition = new Point3D(sampleData.Matrix.M41, sampleData.Matrix.M42, sampleData.Matrix.M43);

            targetObjectPosition.Z -= SamplesDistance * _currentSampleIndex;


            double descriptionBorderXPos = Canvas.GetLeft(DesciptionOuterBorder);
            double descriptionBorderYPos = Canvas.GetTop(DesciptionOuterBorder);

            Point objectPositionOnScreen = Camera1.Point3DTo2D(targetObjectPosition);

            DescriptionConnectionLine.X1 = objectPositionOnScreen.X;
            DescriptionConnectionLine.Y1 = objectPositionOnScreen.Y;
            DescriptionConnectionLine.X2 = descriptionBorderXPos;
            DescriptionConnectionLine.Y2 = descriptionBorderYPos + 20;

            Canvas.SetLeft(DescriptionConnectionRectangle, objectPositionOnScreen.X - (DescriptionConnectionRectangle.Width * 0.5));
            Canvas.SetTop(DescriptionConnectionRectangle, objectPositionOnScreen.Y - (DescriptionConnectionRectangle.Height * 0.5));
        }
        private void CalculateTextBlockPositions(int startTriangleIndiceIndex, out Point[] screenPositions, out int[] indexes)
        {
            indexes = new int[3];

            indexes[0] = _rootMesh.TriangleIndices[startTriangleIndiceIndex];
            indexes[1] = _rootMesh.TriangleIndices[startTriangleIndiceIndex + 1];
            indexes[2] = _rootMesh.TriangleIndices[startTriangleIndiceIndex + 2];

            double sumX = 0;
            double sumY = 0;

            screenPositions = new Point[indexes.Length];

            for (int i = 0; i < indexes.Length; i++)
            {
                Point3D onePosition = _rootMesh.Positions[indexes[i]];

                Point screenPosition = Camera1.Point3DTo2D(onePosition);

                sumX += screenPosition.X;
                sumY += screenPosition.Y;

                screenPositions[i] = screenPosition;
            }

            Point centerScreenPosition = new Point(sumX / indexes.Length, sumY / indexes.Length);

            // Get direction vectors
            for (int i = 0; i < indexes.Length; i++)
            {
                Vector vector = screenPositions[i] - centerScreenPosition;
                vector.Normalize();

                screenPositions[i] += vector * 10; // move text center 10 pixels away from the vertex position
            }
        }
        //public void SetBoxPosition(Vector3D offset)
        //{
        //    AnimatedBoxTranslate.OffsetX = offset.X;
        //    AnimatedBoxTranslate.OffsetY = offset.Y;
        //    AnimatedBoxTranslate.OffsetZ = offset.Z;

        //    UpdateOverlayData();
        //}

        private void UpdateOverlayData()
        {
            //
            // Convert Point3D (sphere's CenterPosition) to 2D position on the screen with using camera.Point3DTo2D method
            //
            var sphereCenterPosition = Sphere1Visual3D.CenterPosition;

            sphereCenterPosition = Sphere1Visual3D.Transform.Transform(sphereCenterPosition);

            var spheresCenterOnScreen = Camera1.Point3DTo2D(sphereCenterPosition);

            // NOTE:
            // The above method requires that the camera is attached to real a Viewport3D
            // If you need to convert 3D coordinates to 2D space without creating Viewport3D,
            // you can use the overloaded method that takes viewportSize as parameter - for example:
            //var targetPositionCamera = new Ab3d.Cameras.TargetPositionCamera()
            //{
            //    Heading = 30,
            //    Attitude = -20,
            //    Distance = 200
            //};
            //var point2D = targetPositionCamera.Point3DTo2D(new Point3D(100, 100, 100), viewportSize: new Size(200, 100));


            // Update UI only when the difference is significant (more than 1 pixel)
            bool isSphere1ScreenPositionChangedSignificantly =
                (Math.Abs(spheresCenterOnScreen.X - _oldSphere1ScreenPosition.X) >= 1.0 ||
                 Math.Abs(spheresCenterOnScreen.Y - _oldSphere1ScreenPosition.Y) >= 1.0);

            if (isSphere1ScreenPositionChangedSignificantly)
            {
                Sphere1ConnectionLine.X1 = spheresCenterOnScreen.X;
                Sphere1ConnectionLine.Y1 = spheresCenterOnScreen.Y;

                Sphere1ConnectionLine.X2 = Sphere1ConnectionLine.X1 + 30;
                Sphere1ConnectionLine.Y2 = Sphere1ConnectionLine.Y1 - 15;


                Sphere1InfoTextBlock.Text = string.Format("Screen position\r\nby Point3DTo2D:\r\nx:{0:0} y:{1:0}",
                                                          spheresCenterOnScreen.X, spheresCenterOnScreen.Y);

                Canvas.SetLeft(Sphere1InfoBorder, spheresCenterOnScreen.X + 29);
                Canvas.SetTop(Sphere1InfoBorder, spheresCenterOnScreen.Y - Sphere1InfoBorder.ActualHeight - 14);

                _oldSphere1ScreenPosition = spheresCenterOnScreen;
            }


            //
            // Convert Rect3D (Box's Bounds) to 2D Rect on the screen with using camera.Rect3DTo2D method
            //
            var boxBounds3D = Box1Visual3D.Content.Bounds;

            boxBounds3D = Box1Visual3D.Transform.TransformBounds(boxBounds3D);

            Rect screenBoxBounds2D = Camera1.Rect3DTo2D(boxBounds3D);


            // Update UI only when the difference is significant (more than 1 pixel)
            if (Math.Abs(screenBoxBounds2D.X - _oldBox1ScreenBounds.X) >= 1.0 ||
                Math.Abs(screenBoxBounds2D.Y - _oldBox1ScreenBounds.Y) >= 1.0 ||
                Math.Abs(screenBoxBounds2D.Width - _oldBox1ScreenBounds.Width) >= 1.0 ||
                Math.Abs(screenBoxBounds2D.Height - _oldBox1ScreenBounds.Height) >= 1.0)
            {
                Canvas.SetLeft(Box1OverlayRectangle, screenBoxBounds2D.X);
                Canvas.SetTop(Box1OverlayRectangle, screenBoxBounds2D.Y);
                Box1OverlayRectangle.Width  = screenBoxBounds2D.Width;
                Box1OverlayRectangle.Height = screenBoxBounds2D.Height;

                Box1ConnectionLine.X1 = screenBoxBounds2D.X + screenBoxBounds2D.Width - 1;
                Box1ConnectionLine.Y1 = screenBoxBounds2D.Y + 1;

                Box1ConnectionLine.X2 = Box1ConnectionLine.X1 + 20;
                Box1ConnectionLine.Y2 = Box1ConnectionLine.Y1 - 10;


                Box1InfoTextBlock.Text = string.Format("Screen bounds by\r\nRect3DTo2D:\r\nx:{0:0} y:{1:0}\r\nw:{2:0} h:{3:0}", screenBoxBounds2D.X, screenBoxBounds2D.Y, screenBoxBounds2D.Width, screenBoxBounds2D.Height);

                Canvas.SetLeft(Box1InfoBorder, screenBoxBounds2D.X + screenBoxBounds2D.Width + 18);
                Canvas.SetTop(Box1InfoBorder, screenBoxBounds2D.Y - Box1InfoBorder.ActualHeight - 8);

                _oldBox1ScreenBounds = screenBoxBounds2D;
            }


            if (isSphere1ScreenPositionChangedSignificantly) // reuse the test done for Sphere1
            {
                var sphereGeometryModel3D = Sphere2Visual3D.Content as GeometryModel3D;

                if (sphereGeometryModel3D != null)
                {
                    var meshGeometry3D = (MeshGeometry3D)sphereGeometryModel3D.Geometry;

                    var positionsCount = meshGeometry3D.Positions.Count;
                    if (_sphere2MeshScreenPositions == null || _sphere2MeshScreenPositions.Length != positionsCount)
                    {
                        // Do not create new array on each UI update
                        _sphere2MeshScreenPositions = new Point[positionsCount];

                        _sphere2Ellipses = new Ellipse[positionsCount];
                        for (int i = 0; i < positionsCount; i++)
                        {
                            var ellipse = new Ellipse()
                            {
                                Fill   = Brushes.Yellow,
                                Width  = 4,
                                Height = 4
                            };

                            OverlayCanvas.Children.Add(ellipse);

                            _sphere2Ellipses[i] = ellipse;
                        }
                    }

                    // Points3DTo2D also support parallel calculations (for lots of positions the perf gains are significant).
                    // Tests show that it is worth using parallel algorithm when number of positions is more the 300 (but this may be highly CPU dependent)
                    bool useParallelFor = positionsCount > 300;

                    bool success = Camera1.Points3DTo2D(points3D: meshGeometry3D.Positions,
                                                        points2D: _sphere2MeshScreenPositions,
                                                        transform: Sphere2Visual3D.Transform,
                                                        useParallelFor: useParallelFor);

                    if (success) // success can be false when the Viewport3D is not initialized (does not have its size) or the camera is not yet initialized
                    {
                        double xSum         = 0;
                        double ySum         = 0;
                        int    samplesCount = 0;

                        double halfEllipseWidth  = _sphere2Ellipses[0].Width / 2;
                        double halfEllipseHeight = _sphere2Ellipses[0].Width / 2;

                        for (var i = 0; i < _sphere2Ellipses.Length; i++)
                        {
                            var ellipse = _sphere2Ellipses[i];

                            double x = _sphere2MeshScreenPositions[i].X;
                            double y = _sphere2MeshScreenPositions[i].Y;

                            if (double.IsNaN(x) || double.IsNaN(y)) // This may happen when object is on the camera's near plane
                            {
                                continue;
                            }

                            Canvas.SetLeft(ellipse, x - halfEllipseWidth);
                            Canvas.SetTop(ellipse, y - halfEllipseHeight);

                            xSum += x;
                            ySum += y;
                            samplesCount++;
                        }


                        // Calculate the center by averaging the screen positions:
                        double xCenter = xSum / samplesCount;
                        double yCenter = ySum / samplesCount;


                        Sphere2ConnectionLine.X1 = xCenter;
                        Sphere2ConnectionLine.Y1 = yCenter;

                        Sphere2ConnectionLine.X2 = xCenter + 49;
                        Sphere2ConnectionLine.Y2 = yCenter - 25;


                        Canvas.SetLeft(Sphere2InfoBorder, xCenter + 49);
                        Canvas.SetTop(Sphere2InfoBorder, yCenter - Sphere2InfoBorder.ActualHeight - 24);
                    }
                }
            }


            //Point3D centerPoint3D;
            //Point centerPoint2D;

            //// In this case we could also calculate centerPoint2D from bounds2D (see commented line below).
            //// But to demonstrate the Point3DTo2D method we are not using bounds2D
            ////centerPoint2D = new Point(bounds2D.X + bounds2D.Width / 2, bounds2D.Y + bounds2D.Height / 2);

            //centerPoint3D = new Point3D(bounds3D.X + bounds3D.SizeX / 2,
            //                            bounds3D.Y + bounds3D.SizeY / 2,
            //                            bounds3D.Z + bounds3D.SizeZ / 2);



            //int segments = 200;
            //bool parallel = false;
            //var sphereMesh3D = new Ab3d.Meshes.SphereMesh3D(new Point3D(0,0,0), 20, segments).Geometry;

            //var points2D = new Point[sphereMesh3D.Positions.Count];
            //var point3Ds = sphereMesh3D.Positions.ToArray();
            ////var point3Ds = sphereMesh3D.Positions;
            ////point3Ds.Freeze();

            //var stopwatch = new Stopwatch();
            //stopwatch.Start();

            //var translateTransform3D = new TranslateTransform3D(100, 0, 0);

            //bool isCorrect = false;
            //for (int i = 0; i < 10; i++)
            //{
            //    isCorrect = Camera1.Points3DTo2D(point3Ds, points2D, translateTransform3D, useParallelFor: parallel);
            //}



            //stopwatch.Stop();

            //if (isCorrect)
            //    MessageBox.Show("Time: " + stopwatch.Elapsed.TotalMilliseconds);



            //for (var i = 0; i < sphereMesh3D.Positions.Count; i++)
            //{
            //    var point3D = point3Ds[i];

            //    if (translateTransform3D != null)
            //        point3D = translateTransform3D.Transform(point3D);

            //    var point2D = Camera1.Point3DTo2D(point3D);
            //    var distance = (point2D - points2D[i]).Length;
            //    if (distance > 0.0001)
            //    {

            //    }
            //}



            // ADDITIONAL NOTE:
            // To convert 3D positions of a 3D LINE to screen positions, use the Line3DTo2D method instead of two calls to Point3DTo2D.
            // The Line3DTo2D method correctly handles the case when the 3D line crosses the camera near plane (goes behind the camera).
            // In this case the line needs to be cropped at the camera near plane, otherwise the results are incorrect.
        }