/// <summary>
        /// The update clipping.
        /// </summary>
        private void UpdateClipping()
        {
            Viewport3D vp = Visual3DHelper.GetViewport3D(this);

            if (vp == null)
            {
                return;
            }

            this.Clipping = new CohenSutherlandClipping(10, vp.ActualWidth - 20, 10, vp.ActualHeight - 20);
        }
        /// <summary>
        /// Creates the positions for the specified line segments.
        /// </summary>
        /// <param name="points">
        /// The points of the line segments.
        /// </param>
        /// <param name="thickness">
        /// The thickness of the line.
        /// </param>
        /// <param name="depthOffset">
        /// The depth offset. A positive number (e.g. 0.0001) moves the point towards the camera.
        /// </param>
        /// <param name="clipping">
        /// The clipping.
        /// </param>
        /// <returns>
        /// The positions collection.
        /// </returns>
        public Point3DCollection CreatePositions(
            IList <Point3D> points,
            double thickness   = 1.0,
            double depthOffset = 0.0,
            CohenSutherlandClipping clipping = null)
        {
            var halfThickness = thickness * 0.5;
            var segmentCount  = points.Count / 2;

            var positions = new Point3DCollection(segmentCount * 4);

            for (int i = 0; i < segmentCount; i++)
            {
                int startIndex = i * 2;

                var startPoint = points[startIndex];
                var endPoint   = points[startIndex + 1];

                // Transform the start and end points to screen space
                var s0 = (Point4D)startPoint * this.visualToScreen;
                var s1 = (Point4D)endPoint * this.visualToScreen;

                if (clipping != null)
                {
                    // Apply a clipping rectangle
                    var x0 = s0.X / s0.W;
                    var y0 = s0.Y / s0.W;
                    var x1 = s1.X / s1.W;
                    var y1 = s1.Y / s1.W;

                    if (!clipping.ClipLine(ref x0, ref y0, ref x1, ref y1))
                    {
                        continue;
                    }

                    s0.X = x0 * s0.W;
                    s0.Y = y0 * s0.W;
                    s1.X = x1 * s1.W;
                    s1.Y = y1 * s1.W;
                }

                var lx = (s1.X / s1.W) - (s0.X / s0.W);
                var ly = (s1.Y / s1.W) - (s0.Y / s0.W);
                var l2 = (lx * lx) + (ly * ly);

                var p00 = s0;
                var p01 = s0;
                var p10 = s1;
                var p11 = s1;

                if (l2.Equals(0))
                {
                    // coinciding points (in world space or screen space)
                    var dz = halfThickness;

                    // TODO: make a square with the thickness as side length
                    p00.X -= dz * p00.W;
                    p00.Y -= dz * p00.W;

                    p01.X -= dz * p01.W;
                    p01.Y += dz * p01.W;

                    p10.X += dz * p10.W;
                    p10.Y -= dz * p10.W;

                    p11.X += dz * p11.W;
                    p11.Y += dz * p11.W;
                }
                else
                {
                    var m = halfThickness / Math.Sqrt(l2);

                    // the normal (dx,dy)
                    var dx = -ly * m;
                    var dy = lx * m;

                    // segment start points
                    p00.X += dx * p00.W;
                    p00.Y += dy * p00.W;
                    p01.X -= dx * p01.W;
                    p01.Y -= dy * p01.W;

                    // segment end points
                    p10.X += dx * p10.W;
                    p10.Y += dy * p10.W;
                    p11.X -= dx * p11.W;
                    p11.Y -= dy * p11.W;
                }

                if (!depthOffset.Equals(0))
                {
                    // Adjust the z-coordinate by the depth offset
                    p00.Z -= depthOffset;
                    p01.Z -= depthOffset;
                    p10.Z -= depthOffset;
                    p11.Z -= depthOffset;

                    // Transform from screen space to world space
                    p00 *= this.screenToVisual;
                    p01 *= this.screenToVisual;
                    p10 *= this.screenToVisual;
                    p11 *= this.screenToVisual;

                    positions.Add(new Point3D(p00.X / p00.W, p00.Y / p00.W, p00.Z / p00.W));
                    positions.Add(new Point3D(p01.X / p00.W, p01.Y / p01.W, p01.Z / p01.W));
                    positions.Add(new Point3D(p10.X / p00.W, p10.Y / p10.W, p10.Z / p10.W));
                    positions.Add(new Point3D(p11.X / p00.W, p11.Y / p11.W, p11.Z / p11.W));
                }
                else
                {
                    // Transform from screen space to world space
                    p00 *= this.screenToVisual;
                    p01 *= this.screenToVisual;
                    p10 *= this.screenToVisual;
                    p11 *= this.screenToVisual;

                    positions.Add(new Point3D(p00.X, p00.Y, p00.Z));
                    positions.Add(new Point3D(p01.X, p01.Y, p01.Z));
                    positions.Add(new Point3D(p10.X, p10.Y, p10.Z));
                    positions.Add(new Point3D(p11.X, p11.Y, p11.Z));
                }
            }

            positions.Freeze();
            return(positions);
        }
        /// <summary>
        /// The update clipping.
        /// </summary>
        private void UpdateClipping()
        {
            Viewport3D vp = Visual3DHelper.GetViewport3D(this);
            if (vp == null)
            {
                return;
            }

            this.Clipping = new CohenSutherlandClipping(10, vp.ActualWidth - 20, 10, vp.ActualHeight - 20);
        }
Exemple #4
0
        /// <summary>
        /// Creates the positions for the specified line segments.
        /// </summary>
        /// <param name="points">
        /// The points of the line segments.
        /// </param>
        /// <param name="thickness">
        /// The thickness of the line.
        /// </param>
        /// <param name="depthOffset">
        /// The depth offset. A positive number (e.g. 0.0001) moves the point towards the camera.
        /// </param>
        /// <param name="clipping">
        /// The clipping.
        /// </param>
        /// <returns>
        /// The positions collection.
        /// </returns>
        public Point3DCollection CreatePositions(
            IList <Point3D> points,
            double thickness   = 1.0,
            double depthOffset = 0.0,
            CohenSutherlandClipping clipping = null)
        {
            double halfThickness = thickness * 0.5;
            int    segmentCount  = points.Count / 2;

            var positions = new Point3DCollection(segmentCount * 4);

            for (int i = 0; i < segmentCount; i++)
            {
                int startIndex = i * 2;

                Point3D startPoint = points[startIndex];
                Point3D endPoint   = points[startIndex + 1];

                var s0 = (Point4D)startPoint * this.visualToScreen;
                var s1 = (Point4D)endPoint * this.visualToScreen;

                if (clipping != null)
                {
                    double x0 = s0.X / s0.W;
                    double y0 = s0.Y / s0.W;
                    double x1 = s1.X / s1.W;
                    double y1 = s1.Y / s1.W;

                    if (!clipping.ClipLine(ref x0, ref y0, ref x1, ref y1))
                    {
                        continue;
                    }

                    s0.X = x0 * s0.W;
                    s0.Y = y0 * s0.W;
                    s1.X = x1 * s1.W;
                    s1.Y = y1 * s1.W;
                }

                double lx = s1.X / s1.W - s0.X / s0.W;
                double ly = s1.Y / s1.W - s0.Y / s0.W;
                double m  = halfThickness / Math.Sqrt(lx * lx + ly * ly);

                double dx = -ly * m;
                double dy = lx * m;

                var p00 = s0;
                var p01 = s0;
                var p10 = s1;
                var p11 = s1;

                p00.X += dx * p00.W;
                p00.Y += dy * p00.W;
                p01.X -= dx * p01.W;
                p01.Y -= dy * p01.W;
                p10.X += dx * p10.W;
                p10.Y += dy * p10.W;
                p11.X -= dx * p11.W;
                p11.Y -= dy * p11.W;
                if (depthOffset != 0)
                {
                    p00.Z -= depthOffset;
                    p01.Z -= depthOffset;
                    p10.Z -= depthOffset;
                    p11.Z -= depthOffset;

                    p00 *= this.screenToVisual;
                    p01 *= this.screenToVisual;
                    p10 *= this.screenToVisual;
                    p11 *= this.screenToVisual;

                    positions.Add(new Point3D(p00.X / p00.W, p00.Y / p00.W, p00.Z / p00.W));
                    positions.Add(new Point3D(p01.X / p00.W, p01.Y / p01.W, p01.Z / p01.W));
                    positions.Add(new Point3D(p10.X / p00.W, p10.Y / p10.W, p10.Z / p10.W));
                    positions.Add(new Point3D(p11.X / p00.W, p11.Y / p11.W, p11.Z / p11.W));
                }
                else
                {
                    p00 *= this.screenToVisual;
                    p01 *= this.screenToVisual;
                    p10 *= this.screenToVisual;
                    p11 *= this.screenToVisual;

                    positions.Add(new Point3D(p00.X, p00.Y, p00.Z));
                    positions.Add(new Point3D(p01.X, p01.Y, p01.Z));
                    positions.Add(new Point3D(p10.X, p10.Y, p10.Z));
                    positions.Add(new Point3D(p11.X, p11.Y, p11.Z));
                }
            }

            positions.Freeze();
            return(positions);
        }
        /// <summary>
        /// Creates the positions for the specified line segments.
        /// </summary>
        /// <param name="points">
        /// The points of the line segments.
        /// </param>
        /// <param name="thickness">
        /// The thickness of the line.
        /// </param>
        /// <param name="depthOffset">
        /// The depth offset. A positive number (e.g. 0.0001) moves the point towards the camera.
        /// </param>
        /// <param name="clipping">
        /// The clipping.
        /// </param>
        /// <returns>
        /// The positions collection.
        /// </returns>
        public Point3DCollection CreatePositions(
            IList<Point3D> points,
            double thickness = 1.0,
            double depthOffset = 0.0,
            CohenSutherlandClipping clipping = null)
        {
            var halfThickness = thickness * 0.5;
            var segmentCount = points.Count / 2;

            var positions = new Point3DCollection(segmentCount * 4);

            for (int i = 0; i < segmentCount; i++)
            {
                int startIndex = i * 2;

                var startPoint = points[startIndex];
                var endPoint = points[startIndex + 1];

                // Transform the start and end points to screen space
                var s0 = (Point4D)startPoint * this.visualToScreen;
                var s1 = (Point4D)endPoint * this.visualToScreen;

                if (clipping != null)
                {
                    // Apply a clipping rectangle
                    var x0 = s0.X / s0.W;
                    var y0 = s0.Y / s0.W;
                    var x1 = s1.X / s1.W;
                    var y1 = s1.Y / s1.W;

                    if (!clipping.ClipLine(ref x0, ref y0, ref x1, ref y1))
                    {
                        continue;
                    }

                    s0.X = x0 * s0.W;
                    s0.Y = y0 * s0.W;
                    s1.X = x1 * s1.W;
                    s1.Y = y1 * s1.W;
                }

                var lx = (s1.X / s1.W) - (s0.X / s0.W);
                var ly = (s1.Y / s1.W) - (s0.Y / s0.W);
                var l2 = (lx * lx) + (ly * ly);

                var p00 = s0;
                var p01 = s0;
                var p10 = s1;
                var p11 = s1;

                if (l2.Equals(0))
                {
                    // coinciding points (in world space or screen space)
                    var dz = halfThickness;

                    // TODO: make a square with the thickness as side length
                    p00.X -= dz * p00.W;
                    p00.Y -= dz * p00.W;
                    
                    p01.X -= dz * p01.W;
                    p01.Y += dz * p01.W;
                    
                    p10.X += dz * p10.W;
                    p10.Y -= dz * p10.W;
                    
                    p11.X += dz * p11.W;                    
                    p11.Y += dz * p11.W;
                }
                else
                {
                    var m = halfThickness / Math.Sqrt(l2);

                    // the normal (dx,dy)
                    var dx = -ly * m;
                    var dy = lx * m;
                    
                    // segment start points
                    p00.X += dx * p00.W;
                    p00.Y += dy * p00.W;
                    p01.X -= dx * p01.W;
                    p01.Y -= dy * p01.W;

                    // segment end points
                    p10.X += dx * p10.W;
                    p10.Y += dy * p10.W;
                    p11.X -= dx * p11.W;
                    p11.Y -= dy * p11.W;
                }

                if (!depthOffset.Equals(0))
                {
                    // Adjust the z-coordinate by the depth offset
                    p00.Z -= depthOffset;
                    p01.Z -= depthOffset;
                    p10.Z -= depthOffset;
                    p11.Z -= depthOffset;

                    // Transform from screen space to world space
                    p00 *= this.screenToVisual;
                    p01 *= this.screenToVisual;
                    p10 *= this.screenToVisual;
                    p11 *= this.screenToVisual;

                    positions.Add(new Point3D(p00.X / p00.W, p00.Y / p00.W, p00.Z / p00.W));
                    positions.Add(new Point3D(p01.X / p00.W, p01.Y / p01.W, p01.Z / p01.W));
                    positions.Add(new Point3D(p10.X / p00.W, p10.Y / p10.W, p10.Z / p10.W));
                    positions.Add(new Point3D(p11.X / p00.W, p11.Y / p11.W, p11.Z / p11.W));
                }
                else
                {
                    // Transform from screen space to world space
                    p00 *= this.screenToVisual;
                    p01 *= this.screenToVisual;
                    p10 *= this.screenToVisual;
                    p11 *= this.screenToVisual;

                    positions.Add(new Point3D(p00.X, p00.Y, p00.Z));
                    positions.Add(new Point3D(p01.X, p01.Y, p01.Z));
                    positions.Add(new Point3D(p10.X, p10.Y, p10.Z));
                    positions.Add(new Point3D(p11.X, p11.Y, p11.Z));
                }
            }

            positions.Freeze();
            return positions;
        }
        /// <summary>
        /// Creates the positions for the specified line segments.
        /// </summary>
        /// <param name="points">
        /// The points of the line segments.
        /// </param>
        /// <param name="thickness">
        /// The thickness of the line.
        /// </param>
        /// <param name="depthOffset">
        /// The depth offset. A positive number (e.g. 0.0001) moves the point towards the camera.
        /// </param>
        /// <param name="clipping">
        /// The clipping.
        /// </param>
        /// <returns>
        /// The positions collection.
        /// </returns>
        public Point3DCollection CreatePositions(
            IList<Point3D> points,
            double thickness = 1.0,
            double depthOffset = 0.0,
            CohenSutherlandClipping clipping = null)
        {
            double halfThickness = thickness * 0.5;
            int segmentCount = points.Count / 2;

            var positions = new Point3DCollection(segmentCount * 4);

            for (int i = 0; i < segmentCount; i++)
            {
                int startIndex = i * 2;

                Point3D startPoint = points[startIndex];
                Point3D endPoint = points[startIndex + 1];

                var s0 = (Point4D)startPoint * this.visualToScreen;
                var s1 = (Point4D)endPoint * this.visualToScreen;

                if (clipping != null)
                {
                    double x0 = s0.X / s0.W;
                    double y0 = s0.Y / s0.W;
                    double x1 = s1.X / s1.W;
                    double y1 = s1.Y / s1.W;

                    if (!clipping.ClipLine(ref x0, ref y0, ref x1, ref y1))
                    {
                        continue;
                    }

                    s0.X = x0 * s0.W;
                    s0.Y = y0 * s0.W;
                    s1.X = x1 * s1.W;
                    s1.Y = y1 * s1.W;
                }

                double lx = s1.X / s1.W - s0.X / s0.W;
                double ly = s1.Y / s1.W - s0.Y / s0.W;
                double m = halfThickness / Math.Sqrt(lx * lx + ly * ly);

                double dx = -ly * m;
                double dy = lx * m;

                var p00 = s0;
                var p01 = s0;
                var p10 = s1;
                var p11 = s1;

                p00.X += dx * p00.W;
                p00.Y += dy * p00.W;
                p01.X -= dx * p01.W;
                p01.Y -= dy * p01.W;
                p10.X += dx * p10.W;
                p10.Y += dy * p10.W;
                p11.X -= dx * p11.W;
                p11.Y -= dy * p11.W;
                if (depthOffset != 0)
                {
                    p00.Z -= depthOffset;
                    p01.Z -= depthOffset;
                    p10.Z -= depthOffset;
                    p11.Z -= depthOffset;

                    p00 *= this.screenToVisual;
                    p01 *= this.screenToVisual;
                    p10 *= this.screenToVisual;
                    p11 *= this.screenToVisual;

                    positions.Add(new Point3D(p00.X / p00.W, p00.Y / p00.W, p00.Z / p00.W));
                    positions.Add(new Point3D(p01.X / p00.W, p01.Y / p01.W, p01.Z / p01.W));
                    positions.Add(new Point3D(p10.X / p00.W, p10.Y / p10.W, p10.Z / p10.W));
                    positions.Add(new Point3D(p11.X / p00.W, p11.Y / p11.W, p11.Z / p11.W));
                }
                else
                {
                    p00 *= this.screenToVisual;
                    p01 *= this.screenToVisual;
                    p10 *= this.screenToVisual;
                    p11 *= this.screenToVisual;

                    positions.Add(new Point3D(p00.X, p00.Y, p00.Z));
                    positions.Add(new Point3D(p01.X, p01.Y, p01.Z));
                    positions.Add(new Point3D(p10.X, p10.Y, p10.Z));
                    positions.Add(new Point3D(p11.X, p11.Y, p11.Z));
                }
            }

            positions.Freeze();
            return positions;
        }