Example #1
0
        /// <inheritdoc/>
        public override Point3D Deproject(Point point, Line3DElement line)
        {
            Point3D rotatedPoint = new Point3D(point.X / ScaleFactor, point.Y / ScaleFactor, 0);

            Point3D projectedPoint   = RotationMatrix.Inverse() * (CameraRotationMatrix.Inverse() * rotatedPoint);
            Point3D cameraPlanePoint = projectedPoint + (Vector3D)this.Position;

            NormalizedVector3D v = this.Direction;
            NormalizedVector3D l = (line[1] - line[0]).Normalize();

            double t;

            if (v.X * l.Y - v.Y * l.X != 0)
            {
                t = (l.X * (cameraPlanePoint.Y - line[0].Y) - l.Y * (cameraPlanePoint.X - line[0].X)) / (v.X * l.Y - v.Y * l.X);
            }
            else if (v.Z * l.Y - v.Y * l.Z != 0)
            {
                t = (l.Z * (cameraPlanePoint.Y - line[0].Y) - l.Y * (cameraPlanePoint.Z - line[0].Z)) / (v.Z * l.Y - v.Y * l.Z);
            }
            else if (v.Z * l.X - v.X * l.Z != 0)
            {
                t = (l.Z * (cameraPlanePoint.X - line[0].X) - l.X * (cameraPlanePoint.Z - line[0].Z)) / (v.Z * l.X - v.X * l.Z);
            }
            else
            {
                throw new Exception("The lines do not intersect!");
            }

            Point3D pt = cameraPlanePoint + v * t;

            return(pt);
        }
Example #2
0
        /// <summary>
        /// Applies the transformation to a <see cref="Line3DElement"/>.
        /// </summary>
        /// <param name="line">The <see cref="Line3DElement"/> to which the transformation should be applied.</param>
        /// <returns>A <see cref="Line3DElement"/> corresponding to a line in which the transformation has been applied to the points from <paramref name="line" />. Properties are preserved between the two elements.</returns>
        public Line3DElement Apply(Line3DElement line)
        {
            Point3D p1 = this.Apply(line.Point1);
            Point3D p2 = this.Apply(line.Point2);

            Line3DElement tbr = new Line3DElement(p1, p2)
            {
                Colour = line.Colour, LineCap = line.LineCap, LineDash = line.LineDash, Thickness = line.Thickness, Tag = line.Tag, ZIndex = line.ZIndex
            };

            return(tbr);
        }
Example #3
0
        private unsafe void DrawLine(byte *imageData, Line3DElement line, Camera camera)
        {
            Point[] line2D = line.GetProjection();

            int minX = int.MaxValue;
            int minY = int.MaxValue;

            int maxX = int.MinValue;
            int maxY = int.MinValue;

            for (int i = 0; i < line2D.Length; i++)
            {
                line2D[i] = new Point((line2D[i].X - camera.TopLeft.X) / camera.Size.Width * this.RenderWidth, (line2D[i].Y - camera.TopLeft.Y) / camera.Size.Height * this.RenderHeight);

                minX = Math.Min(minX, (int)line2D[i].X);
                minY = Math.Min(minY, (int)line2D[i].Y);

                maxX = Math.Max(maxX, (int)Math.Ceiling(line2D[i].X));
                maxY = Math.Max(maxY, (int)Math.Ceiling(line2D[i].Y));
            }



            double thicknessX      = line.Thickness * 0.5 / camera.Size.Width * this.RenderWidth;
            double thicknessY      = line.Thickness * 0.5 / camera.Size.Height * this.RenderHeight;
            double thicknessSquare = thicknessY * thicknessX;
            double thickness       = Math.Sqrt(thicknessSquare);

            minX = (int)Math.Floor(minX - thicknessX);
            minY = (int)Math.Floor(minY - thicknessY);
            maxX = (int)Math.Ceiling(maxX + thicknessX);
            maxY = (int)Math.Ceiling(maxY + thicknessY);


            minX = Math.Max(minX, 0);
            minY = Math.Max(minY, 0);

            maxX = Math.Min(maxX, this.RenderWidth - 1);
            maxY = Math.Min(maxY, this.RenderHeight - 1);

            int totalPixels = (maxX - minX + 1) * (maxY - minY + 1);

            double lineLengthSq = (line2D[1].X - line2D[0].X) * (line2D[1].X - line2D[0].X) + (line2D[1].Y - line2D[0].Y) * (line2D[1].Y - line2D[0].Y);
            double lineLength   = Math.Sqrt(lineLengthSq);
            double addedTerm    = line2D[1].X * line2D[0].Y - line2D[1].Y * line2D[0].X;
            double dy           = line2D[1].Y - line2D[0].Y;
            double dx           = line2D[1].X - line2D[0].X;

            double unitsOn  = (line.LineDash.UnitsOn / line.Thickness * thickness * 2) / lineLength;
            double unitsOff = (line.LineDash.UnitsOff / line.Thickness * thickness * 2) / lineLength;
            double phase    = (line.LineDash.Phase / line.Thickness * thickness * 2) / lineLength;

            bool dashOn(double t)
            {
                if (unitsOff == 0)
                {
                    return(true);
                }
                else
                {
                    t += phase;
                    t  = t % (unitsOn + unitsOff);
                    while (t < 0)
                    {
                        t += unitsOn + unitsOff;
                    }

                    return(t <= unitsOn);
                }
            };

            Parallel.For(0, totalPixels, index =>
            {
                int y = index / (maxX - minX + 1) + minY;
                int x = index % (maxX - minX + 1) + minX;

                double dist = Math.Abs(dy * x - dx * y + addedTerm) / lineLength;

                double howMuch = dist <= thickness ? 1 : Math.Max(0, 1 - (dist - thickness));

                if (howMuch > 0)
                {
                    (double t, Point pointOnLine) = Intersections2D.ProjectOnSegment(x, y, line2D[0], line2D[1]);

                    if (line.LineCap == LineCaps.Butt)
                    {
                        if (t < 0)
                        {
                            howMuch *= Math.Max(0, 1 + t * lineLength);
                        }
                        else if (t > 1)
                        {
                            howMuch *= Math.Max(0, 1 - (t - 1) * lineLength);
                        }
                    }
                    else if (line.LineCap == LineCaps.Square)
                    {
                        if (t < -thickness / lineLength)
                        {
                            howMuch *= Math.Max(0, 1 + (t + thickness / lineLength) * lineLength);
                        }
                        else if (t > 1 + thickness / lineLength)
                        {
                            howMuch *= Math.Max(0, 1 - (t - thickness / lineLength - 1) * lineLength);
                        }
                    }
                    else if (line.LineCap == LineCaps.Round)
                    {
                        if (t < -(thickness + 1) / lineLength || t > 1 + (thickness + 1) / lineLength)
                        {
                            howMuch = 0;
                        }
                        else if (t < 0)
                        {
                            double tipDist = (x - line2D[0].X) * (x - line2D[0].X) + (y - line2D[0].Y) * (y - line2D[0].Y);
                            howMuch       *= tipDist <= thicknessSquare ? 1 : Math.Max(0, 1 - (Math.Sqrt(tipDist) - thickness));
                        }
                        else if (t > 1)
                        {
                            double tipDist = (x - line2D[1].X) * (x - line2D[1].X) + (y - line2D[1].Y) * (y - line2D[1].Y);
                            howMuch       *= tipDist <= thicknessSquare ? 1 : Math.Max(0, 1 - (Math.Sqrt(tipDist) - thickness));
                        }
                    }

                    if (howMuch > 0 && dashOn(t))
                    {
                        Point3D correspPoint = camera.Deproject(new Point((double)pointOnLine.X / this.RenderWidth * camera.Size.Width + camera.TopLeft.X, (double)pointOnLine.Y / this.RenderHeight * camera.Size.Height + camera.TopLeft.Y), line);

                        double zDepth = camera.ZDepth(correspPoint);

                        int prevZIndexBuffer = ZIndexBuffer[y * RenderWidth + x];

                        if (prevZIndexBuffer < line.ZIndex || (prevZIndexBuffer == line.ZIndex && ZBuffer[y * RenderWidth + x] >= zDepth))
                        {
                            byte R = (byte)(line.Colour.R * 255);
                            byte G = (byte)(line.Colour.G * 255);
                            byte B = (byte)(line.Colour.B * 255);
                            byte A = (byte)(line.Colour.A * 255 * howMuch);

                            if (A == 255)
                            {
                                imageData[y * RenderWidth * 4 + x * 4]     = R;
                                imageData[y * RenderWidth * 4 + x * 4 + 1] = G;
                                imageData[y * RenderWidth * 4 + x * 4 + 2] = B;
                                imageData[y * RenderWidth * 4 + x * 4 + 3] = A;
                            }
                            else
                            {
                                BlendFront(ref imageData[y * RenderWidth * 4 + x * 4], ref imageData[y * RenderWidth * 4 + x * 4 + 1], ref imageData[y * RenderWidth * 4 + x * 4 + 2], ref imageData[y * RenderWidth * 4 + x * 4 + 3], R, G, B, A);
                            }

                            ZBuffer[y * RenderWidth + x]      = zDepth;
                            ZIndexBuffer[y * RenderWidth + x] = line.ZIndex;
                        }
                        else if (imageData[y * RenderWidth * 4 + x * 4 + 3] < 255)
                        {
                            byte R = (byte)(line.Colour.R * 255);
                            byte G = (byte)(line.Colour.G * 255);
                            byte B = (byte)(line.Colour.B * 255);
                            byte A = (byte)(line.Colour.A * 255 * howMuch);

                            BlendBack(R, G, B, A, ref imageData[y * RenderWidth * 4 + x * 4], ref imageData[y * RenderWidth * 4 + x * 4 + 1], ref imageData[y * RenderWidth * 4 + x * 4 + 2], ref imageData[y * RenderWidth * 4 + x * 4 + 3]);
                        }
                    }
                }
            });
        }
Example #4
0
        private IEnumerable <Element3D> Resample(Camera camera, Element3D element, double maxSize)
        {
            if (element is Point3DElement)
            {
                yield return(element);
            }
            else if (element is Line3DElement line)
            {
                if (this.ResampleLines)
                {
                    Point p1 = camera.Project(line.Point1);
                    Point p2 = camera.Project(line.Point2);

                    if ((p1.X - p2.X) * (p1.X - p2.X) + (p1.Y - p2.Y) * (p1.Y - p2.Y) > maxSize)
                    {
                        Point3D half = (Point3D)(((Vector3D)line.Point1 + (Vector3D)line.Point2) * 0.5);

                        Line3DElement line1 = new Line3DElement(line.Point1, half)
                        {
                            Colour = line.Colour, LineCap = line.LineCap, LineDash = line.LineDash, Tag = line.Tag, Thickness = line.Thickness, ZIndex = line.ZIndex
                        };
                        Line3DElement line2 = new Line3DElement(half, line.Point2)
                        {
                            Colour = line.Colour, LineCap = line.LineCap, LineDash = line.LineDash, Tag = line.Tag, Thickness = line.Thickness, ZIndex = line.ZIndex
                        };

                        foreach (Element3D el in Resample(camera, line1, maxSize))
                        {
                            yield return(el);
                        }

                        foreach (Element3D el in Resample(camera, line2, maxSize))
                        {
                            yield return(el);
                        }
                    }
                    else
                    {
                        yield return(element);
                    }
                }
                else
                {
                    yield return(element);
                }
            }
            else if (element is Triangle3DElement triangle && element is IVectorRendererTriangle3DElement vectorRendererTriangle)
            {
                Point p1 = camera.Project(triangle.Point1);
                Point p2 = camera.Project(triangle.Point2);
                Point p3 = camera.Project(triangle.Point3);

                double area = 0.5 * Math.Abs((p2.X - p1.X) * (p3.Y - p1.Y) - (p2.Y - p1.Y) * (p3.X - p1.X));

                if (area > maxSize)
                {
                    Point3D proj12 = (Point3D)((triangle.Point2 - triangle.Point1) * 0.5 + triangle.Point1);
                    Point3D proj23 = (Point3D)((triangle.Point3 - triangle.Point2) * 0.5 + triangle.Point2);
                    Point3D proj31 = (Point3D)((triangle.Point1 - triangle.Point3) * 0.5 + triangle.Point3);

                    NormalizedVector3D proj12Normal = (triangle.Point1Normal * 0.5 + triangle.Point2Normal * 0.5).Normalize();
                    NormalizedVector3D proj23Normal = (triangle.Point2Normal * 0.5 + triangle.Point3Normal * 0.5).Normalize();
                    NormalizedVector3D proj31Normal = (triangle.Point3Normal * 0.5 + triangle.Point1Normal * 0.5).Normalize();

                    VectorRendererTriangle3DElement t1 = new VectorRendererTriangle3DElement(triangle.Point1, proj12, proj31, triangle.Point1Normal, proj12Normal, proj31Normal)
                    {
                        Tag = triangle.Tag, ZIndex = triangle.ZIndex, OverFill = vectorRendererTriangle.OverFill, CastsShadow = triangle.CastsShadow, ReceivesShadow = triangle.ReceivesShadow
                    };
                    t1.Fill.AddRange(triangle.Fill);
                    t1.Parent = vectorRendererTriangle.Parent ?? triangle;
                    VectorRendererTriangle3DElement t2 = new VectorRendererTriangle3DElement(triangle.Point2, proj23, proj12, triangle.Point2Normal, proj23Normal, proj12Normal)
                    {
                        Tag = triangle.Tag, ZIndex = triangle.ZIndex, OverFill = vectorRendererTriangle.OverFill, CastsShadow = triangle.CastsShadow, ReceivesShadow = triangle.ReceivesShadow
                    };
                    t2.Fill.AddRange(triangle.Fill);
                    t2.Parent = vectorRendererTriangle.Parent ?? triangle;
                    VectorRendererTriangle3DElement t3 = new VectorRendererTriangle3DElement(triangle.Point3, proj31, proj23, triangle.Point3Normal, proj31Normal, proj23Normal)
                    {
                        Tag = triangle.Tag, ZIndex = triangle.ZIndex, OverFill = vectorRendererTriangle.OverFill, CastsShadow = triangle.CastsShadow, ReceivesShadow = triangle.ReceivesShadow
                    };
                    t3.Fill.AddRange(triangle.Fill);
                    t3.Parent = vectorRendererTriangle.Parent ?? triangle;
                    VectorRendererTriangle3DElement t4 = new VectorRendererTriangle3DElement(proj12, proj23, proj31, proj12Normal, proj23Normal, proj31Normal)
                    {
                        Tag = triangle.Tag, ZIndex = triangle.ZIndex, OverFill = vectorRendererTriangle.OverFill, CastsShadow = triangle.CastsShadow, ReceivesShadow = triangle.ReceivesShadow
                    };
                    t4.Fill.AddRange(triangle.Fill);
                    t4.Parent = vectorRendererTriangle.Parent ?? triangle;

                    foreach (Element3D el in Resample(camera, t1, maxSize))
                    {
                        yield return(el);
                    }

                    foreach (Element3D el in Resample(camera, t2, maxSize))
                    {
                        yield return(el);
                    }

                    foreach (Element3D el in Resample(camera, t3, maxSize))
                    {
                        yield return(el);
                    }

                    foreach (Element3D el in Resample(camera, t4, maxSize))
                    {
                        yield return(el);
                    }
                }
                else
                {
                    yield return(element);
                }
            }
        }
Example #5
0
 /// <summary>
 /// Projects a <see cref="Point"/> in 2D units to obtain the corresponding <see cref="Point3D"/> on the specified element.
 /// </summary>
 /// <param name="point">The <see cref="Point"/> to project.</param>
 /// <param name="element">The <see cref="Line3DElement"/> on which the point should be projected.</param>
 /// <returns>A <see cref="Point3D"/> corresponding to the point on <paramref name="element"/> that, when projected with the current camera, corresponds to <paramref name="point"/>.</returns>
 public abstract Point3D Deproject(Point point, Line3DElement element);
Example #6
0
 public LineEnumerator(Line3DElement line)
 {
     this.Line = line;
 }