Ejemplo n.º 1
0
        public static List <Point> Intersect(Point l11, Point l12, Point A, Point B, Point C, double tolerance)
        {
            Point intersAB = Intersections2D.IntersectFastWithTriangle(l11, l12, A, B, tolerance);
            Point intersBC = Intersections2D.IntersectFastWithTriangle(l11, l12, B, C, tolerance);
            Point intersCA = Intersections2D.IntersectFastWithTriangle(l11, l12, C, A, tolerance);

            List <Point> intersections = new List <Point>(3);

            if (!double.IsNaN(intersAB.X))
            {
                intersections.Add(intersAB);
            }

            if (!double.IsNaN(intersBC.X) && (intersections.Count == 0 || !AreEqual(intersections[0], intersBC, tolerance)))
            {
                intersections.Add(intersBC);
            }

            if (!double.IsNaN(intersCA.X) && (intersections.Count == 0 || (!AreEqual(intersections[0], intersCA, tolerance) && (intersections.Count == 1 || !AreEqual(intersections[1], intersCA, tolerance)))))
            {
                intersections.Add(intersCA);
            }

            return(intersections);
        }
Ejemplo n.º 2
0
        private unsafe void FillTriangleWithShadow(byte *imageData, Triangle3DElement triangle, Camera camera, List <ILightSource> lights, List <Triangle3DElement> shadowers)
        {
            Point[] triangle2D = triangle.GetProjection();

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

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

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

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

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

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

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

            List <Triangle3DElement> otherShadowers = new List <Triangle3DElement>(shadowers.Count);

            for (int i = 0; i < shadowers.Count; i++)
            {
                if (shadowers[i] != triangle)
                {
                    otherShadowers.Add(shadowers[i]);
                }
            }

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

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

                if (Intersections2D.PointInTriangle(x, y, triangle2D[0], triangle2D[1], triangle2D[2]))
                {
                    Point3D correspPoint = camera.Deproject(new Point((double)x / this.RenderWidth * camera.Size.Width + camera.TopLeft.X, (double)y / this.RenderHeight * camera.Size.Height + camera.TopLeft.Y), triangle);

                    double zDepth = camera.ZDepth(correspPoint);

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

                    if (prevZIndexBuffer < triangle.ZIndex || (prevZIndexBuffer == triangle.ZIndex && ZBuffer[y * RenderWidth + x] > zDepth))
                    {
                        (byte R, byte G, byte B, byte A) = GetPixelColorWithShadow(triangle, lights, otherShadowers, x, y, correspPoint, camera);

                        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] = triangle.ZIndex;
                    }
                    else if (imageData[y * RenderWidth * 4 + x * 4 + 3] < 255)
                    {
                        (byte R, byte G, byte B, byte A) = GetPixelColorWithShadow(triangle, lights, otherShadowers, x, y, correspPoint, camera);

                        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]);
                    }
                }
            });
        }
Ejemplo n.º 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]);
                        }
                    }
                }
            });
        }
Ejemplo n.º 4
0
        private unsafe void FillTriangle(byte *imageData, Triangle3DElement triangle, Camera camera, List <ILightSource> lights, List <double> obstructions)
        {
            Point[] triangle2D = triangle.GetProjection();

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

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

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

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

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

            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);

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

                if (Intersections2D.PointInTriangle(x, y, triangle2D[0], triangle2D[1], triangle2D[2]))
                {
                    Point3D correspPoint = camera.Deproject(new Point((double)x / this.RenderWidth * camera.Size.Width + camera.TopLeft.X, (double)y / this.RenderHeight * camera.Size.Height + camera.TopLeft.Y), triangle);

                    double zDepth = camera.ZDepth(correspPoint);

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

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

                        for (int i = 0; i < triangle.Fill.Count; i++)
                        {
                            Colour col = triangle.Fill[i].GetColour(correspPoint, triangle.GetNormalAt(correspPoint), camera, lights, obstructions);

                            if (col.A == 1)
                            {
                                R = (byte)(col.R * 255);
                                G = (byte)(col.G * 255);
                                B = (byte)(col.B * 255);
                                A = (byte)(col.A * 255);
                            }
                            else
                            {
                                BlendFront(ref R, ref G, ref B, ref A, (byte)(col.R * 255), (byte)(col.G * 255), (byte)(col.B * 255), (byte)(col.A * 255));
                            }
                        }

                        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] = triangle.ZIndex;
                    }
                    else if (imageData[y * RenderWidth * 4 + x * 4 + 3] < 255)
                    {
                        byte R = 0;
                        byte G = 0;
                        byte B = 0;
                        byte A = 0;

                        for (int i = 0; i < triangle.Fill.Count; i++)
                        {
                            Colour col = triangle.Fill[i].GetColour(correspPoint, triangle.GetNormalAt(correspPoint), camera, lights, obstructions);

                            if (col.A == 1)
                            {
                                R = (byte)(col.R * 255);
                                G = (byte)(col.G * 255);
                                B = (byte)(col.B * 255);
                                A = (byte)(col.A * 255);
                            }
                            else
                            {
                                BlendFront(ref R, ref G, ref B, ref A, (byte)(col.R * 255), (byte)(col.G * 255), (byte)(col.B * 255), (byte)(col.A * 255));
                            }
                        }

                        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]);
                    }
                }
            });
        }
Ejemplo n.º 5
0
        private (byte R, byte G, byte B, byte A) GetPixelColor(Point point, List <Element3D> elements, Camera camera, List <ILightSource> lights, List <Triangle3DElement> shadowers, List <double> noObstructions, bool reproject)
        {
            List <(Element3D element, double z, Point3D correspPoint)> hits = new List <(Element3D element, double z, Point3D correspPoint)>();

            foreach (Element3D element in elements)
            {
                if (element is Triangle3DElement triangle)
                {
                    Point[] projection;

                    if (reproject)
                    {
                        projection = new Point[] { camera.Project(triangle[0]), camera.Project(triangle[1]), camera.Project(triangle[2]) };
                    }
                    else
                    {
                        projection = triangle.GetProjection();
                    }


                    if (Intersections2D.PointInTriangle(point, projection[0], projection[1], projection[2]))
                    {
                        Point3D correspPoint = camera.Deproject(point, triangle);

                        double z = camera.ZDepth(correspPoint);

                        hits.Add((triangle, z, correspPoint));
                    }
                }
                else if (element is Point3DElement pointElement)
                {
                    Point projection;

                    if (reproject)
                    {
                        projection = camera.Project(pointElement[0]);
                    }
                    else
                    {
                        projection = pointElement.GetProjection()[0];
                    }

                    if ((point.X - projection.X) * (point.X - projection.X) + (point.Y - projection.Y) * (point.Y - projection.Y) <= pointElement.Diameter * pointElement.Diameter * 0.25)
                    {
                        double z = camera.ZDepth(pointElement.Point);

                        hits.Add((pointElement, z, pointElement.Point));
                    }
                }
                else if (element is Line3DElement line)
                {
                    Point[] line2D;

                    if (reproject)
                    {
                        line2D = new Point[] { camera.Project(line[0]), camera.Project(line[1]) };
                    }
                    else
                    {
                        line2D = line.GetProjection();
                    }

                    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 / lineLength;
                    double unitsOff = line.LineDash.UnitsOff / lineLength;
                    double phase    = line.LineDash.Phase / lineLength;

                    double dist = Math.Abs(dy * point.X - dx * point.Y + addedTerm) / lineLength;

                    double thickness = line.Thickness * 0.5;

                    if (dist < thickness)
                    {
                        (double t, Point pointOnLine) = Intersections2D.ProjectOnSegment(point, line2D[0], line2D[1]);

                        bool isIn = false;

                        if (line.LineCap == LineCaps.Butt)
                        {
                            if (t >= 0 && t <= 1)
                            {
                                isIn = true;
                            }
                        }
                        else if (line.LineCap == LineCaps.Square)
                        {
                            if (t >= -thickness / lineLength && t <= 1 + thickness / lineLength)
                            {
                                isIn = true;
                            }
                        }
                        else if (line.LineCap == LineCaps.Round)
                        {
                            if (t >= 0 && t <= 1)
                            {
                                isIn = true;
                            }
                            else if (t < -thickness / lineLength || t > 1 + thickness / lineLength)
                            {
                                isIn = false;
                            }
                            else if (t < 0)
                            {
                                double tipDist = (point.X - line2D[0].X) * (point.X - line2D[0].X) + (point.Y - line2D[0].Y) * (point.Y - line2D[0].Y);

                                if (tipDist <= thickness * thickness)
                                {
                                    isIn = true;
                                }
                            }
                            else if (t > 1)
                            {
                                double tipDist = (point.X - line2D[1].X) * (point.X - line2D[1].X) + (point.Y - line2D[1].Y) * (point.Y - line2D[1].Y);

                                if (tipDist <= thickness * thickness)
                                {
                                    isIn = true;
                                }
                            }
                        }

                        if (isIn && IsDashOn(unitsOn, unitsOff, phase, t))
                        {
                            Point3D correspPoint = camera.Deproject(pointOnLine, line);

                            double z = camera.ZDepth(correspPoint);

                            hits.Add((line, z, correspPoint));
                        }
                    }
                }
            }

            hits.Sort((a, b) =>
            {
                if (a.element.ZIndex == b.element.ZIndex)
                {
                    return(Math.Sign(a.z - b.z));
                }
                else
                {
                    return(Math.Sign(b.element.ZIndex - a.element.ZIndex));
                }
            });

            byte pixelR = 0;
            byte pixelG = 0;
            byte pixelB = 0;
            byte pixelA = 0;

            foreach ((Element3D element, double z, Point3D correspPoint)hit in hits)
            {
                byte R = 0;
                byte G = 0;
                byte B = 0;
                byte A = 0;

                if (hit.element is Triangle3DElement triangle)
                {
                    if (!triangle.ReceivesShadow || shadowers == null)
                    {
                        (R, G, B, A) = GetPixelColor(triangle, hit.correspPoint, camera, lights, noObstructions);
                    }
                    else
                    {
                        (R, G, B, A) = GetPixelColorWithShadow(triangle, lights, shadowers, hit.correspPoint, camera);
                    }
                }
                else if (hit.element is Point3DElement pointElement)
                {
                    R = (byte)(pointElement.Colour.R * 255);
                    G = (byte)(pointElement.Colour.G * 255);
                    B = (byte)(pointElement.Colour.B * 255);
                    A = (byte)(pointElement.Colour.A * 255);
                }
                else if (hit.element is Line3DElement lineElement)
                {
                    R = (byte)(lineElement.Colour.R * 255);
                    G = (byte)(lineElement.Colour.G * 255);
                    B = (byte)(lineElement.Colour.B * 255);
                    A = (byte)(lineElement.Colour.A * 255);
                }

                BlendBack(R, G, B, A, ref pixelR, ref pixelG, ref pixelB, ref pixelA);

                if (pixelA == 255)
                {
                    break;
                }
            }

            return(pixelR, pixelG, pixelB, pixelA);
        }
Ejemplo n.º 6
0
        private void FillTriangle(Graphics graphics, IEnumerable <Point> triangleProjection, Colour colour, double overFill, double scaleFactor, string tag)
        {
            GraphicsPath path = new GraphicsPath();

            if (overFill > 0)
            {
                double overfill = overFill * scaleFactor;

                double meanX = 0;
                double meanY = 0;

                int count = 0;

                foreach (Point pt in triangleProjection)
                {
                    meanX += pt.X;
                    meanY += pt.Y;
                    count++;
                }

                meanX /= count;
                meanY /= count;

                Point centroid2D = new Point(meanX, meanY);

                Point prevPoint  = new Point();
                Point firstPoint = new Point();

                foreach (Point pt in triangleProjection)
                {
                    if (path.Segments.Count == 0)
                    {
                        path.MoveTo(pt);
                        prevPoint  = pt;
                        firstPoint = pt;
                    }
                    else
                    {
                        Point meanPoint = Intersections2D.ProjectOnLine(centroid2D, prevPoint, pt);

                        Point  dir    = new Point(meanPoint.X - meanX, meanPoint.Y - meanY);
                        double length = dir.Modulus();

                        Point newMeanPoint = new Point(meanX + dir.X * (length + overfill) / length, meanY + dir.Y * (length + overfill) / length);

                        path.LineTo(prevPoint.X - meanPoint.X + newMeanPoint.X, prevPoint.Y - meanPoint.Y + newMeanPoint.Y);

                        path.LineTo(pt.X - meanPoint.X + newMeanPoint.X, pt.Y - meanPoint.Y + newMeanPoint.Y);

                        path.LineTo(pt);

                        prevPoint = pt;
                    }
                }

                {
                    Point meanPoint = Intersections2D.ProjectOnLine(centroid2D, prevPoint, firstPoint);

                    Point  dir    = new Point(meanPoint.X - meanX, meanPoint.Y - meanY);
                    double length = dir.Modulus();

                    Point newMeanPoint = new Point(meanX + dir.X * (length + overfill) / length, meanY + dir.Y * (length + overfill) / length);

                    path.LineTo(prevPoint.X - meanPoint.X + newMeanPoint.X, prevPoint.Y - meanPoint.Y + newMeanPoint.Y);

                    path.LineTo(firstPoint.X - meanPoint.X + newMeanPoint.X, firstPoint.Y - meanPoint.Y + newMeanPoint.Y);
                }
            }
            else
            {
                foreach (Point pt in triangleProjection)
                {
                    path.LineTo(pt);
                }
            }

            path.Close();

            graphics.FillPath(path, colour, tag: tag);
        }
Ejemplo n.º 7
0
        /// <summary>
        /// Compares two <see cref="Element3D"/>s to determine which one lies on top of the other when viewed with the current camera.
        /// </summary>
        /// <param name="element1">The first element. If this element is in front, the function returns 1.</param>
        /// <param name="element2">The second element. If this element is in front, the function returns -1.</param>
        /// <returns>1 if <paramref name="element1"/> is in front of <paramref name="element2"/>; -1 if <paramref name="element2"/> is in front of <paramref name="element1"/>; 0 if the two elements do not overlap, intersect or if the order could not be determined for other reasons. </returns>
        public virtual int Compare(Element3D element1, Element3D element2)
        {
            if (element1.ZIndex != element2.ZIndex)
            {
                return(element1.ZIndex - element2.ZIndex);
            }

            if (element1 is Point3DElement pt1)
            {
                Point proj1 = this.Project(pt1[0]);

                if (element2 is Point3DElement pt2)
                {
                    Point proj2 = this.Project(pt2[0]);

                    if ((proj1.X - proj2.X) * (proj1.X - proj2.X) + (proj1.Y - proj2.Y) * (proj1.Y - proj2.Y) < (pt1.Diameter * 0.5 + pt2.Diameter * 0.5) * (pt1.Diameter * 0.5 + pt2.Diameter * 0.5))
                    {
                        double dist1 = this.ZDepth(pt1[0]);
                        double dist2 = this.ZDepth(pt2[0]);

                        if (Math.Abs(dist1 - dist2) < Camera.Tolerance)
                        {
                            return(0);
                        }

                        return(-Math.Sign(dist1 - dist2));
                    }
                    else
                    {
                        return(0);
                    }
                }
                else if (element2 is Line3DElement line)
                {
                    Point p0 = proj1;

                    Point p1 = this.Project(line[0]);
                    Point p2 = this.Project(line[1]);

                    double distSq = ((p2.Y - p1.Y) * p0.X - (p2.X - p1.X) * p0.Y + p2.X * p1.Y - p2.Y * p1.X) * ((p2.Y - p1.Y) * p0.X - (p2.X - p1.X) * p0.Y + p2.X * p1.Y - p2.Y * p1.X) / ((p2.X - p1.X) * (p2.X - p1.X) + (p2.Y - p1.Y) * (p2.Y - p1.Y));

                    double maxDistSq = (pt1.Diameter * 0.5 + line.Thickness * 0.5) * (pt1.Diameter * 0.5 + line.Thickness * 0.5);

                    Point v1 = new Point(p0.X - p1.X, p0.Y - p1.Y);
                    Point v2 = new Point(p2.X - p1.X, p2.Y - p1.Y);

                    double v2Length = v2.Modulus();

                    Point e2 = new Point(v2.X / v2Length, v2.Y / v2Length);

                    double dotProd = v1.X * e2.X + v1.Y * e2.Y;

                    if (dotProd >= -Math.Sqrt(maxDistSq) && dotProd <= v2Length + Math.Sqrt(maxDistSq) && distSq < maxDistSq)
                    {
                        Point pointOnLine = new Point(p1.X + dotProd * e2.X, p1.Y + dotProd * e2.Y);
                        try
                        {
                            Point3D pt = this.Deproject(pointOnLine, line);

                            double dist1 = this.ZDepth(pt1[0]);
                            double dist2 = this.ZDepth(pt);

                            if (Math.Abs(dist1 - dist2) < Camera.Tolerance)
                            {
                                return(0);
                            }

                            return(-Math.Sign(dist1 - dist2));
                        }
                        catch
                        {
                            return(0);
                        }
                    }
                    else
                    {
                        return(0);
                    }
                }
                else if (element2 is Triangle3DElement triangle)
                {
                    Point p0 = proj1;

                    Point p1 = this.Project(triangle[0]);
                    Point p2 = this.Project(triangle[1]);
                    Point p3 = this.Project(triangle[2]);

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

                    double s = 1 / (2 * area) * (p1.Y * p3.X - p1.X * p3.Y + (p3.Y - p1.Y) * p0.X + (p1.X - p3.X) * p0.Y);
                    double t = 1 / (2 * area) * (p1.X * p2.Y - p1.Y * p2.X + (p1.Y - p2.Y) * p0.X + (p2.X - p1.X) * p0.Y);

                    if (s >= 0 && t >= 0 && 1 - s - t >= 0)
                    {
                        Point3D pt = this.Deproject(p0, triangle);

                        double dist1 = this.ZDepth(pt1[0]);
                        double dist2 = this.ZDepth(pt);

                        if (Math.Abs(dist1 - dist2) < Camera.Tolerance)
                        {
                            return(0);
                        }

                        return(-Math.Sign(dist1 - dist2));
                    }
                    else
                    {
                        return(0);
                    }
                }
                else
                {
                    throw new NotImplementedException();
                }
            }
            else if (element1 is Line3DElement line1)
            {
                if (element2 is Point3DElement)
                {
                    return(-Compare(element2, element1));
                }
                else if (element2 is Line3DElement line2)
                {
                    Point l11 = this.Project(line1[0]);
                    Point l12 = this.Project(line1[1]);

                    Point l21 = this.Project(line2[0]);
                    Point l22 = this.Project(line2[1]);


                    (Point inters, double t, double s)? intersection = Intersections2D.Intersect(l11, l12, l21, l22);

                    if (intersection != null)
                    {
                        double vLength = new Point(l12.X - l11.X, l12.Y - l11.Y).Modulus();
                        double lLength = new Point(l22.X - l21.X, l22.Y - l21.Y).Modulus();

                        if (intersection?.t >= -line1.Thickness && intersection?.t <= vLength + line1.Thickness && intersection?.s >= -line1.Thickness && intersection?.s <= lLength + line1.Thickness)
                        {
                            try
                            {
                                Point3D point1 = this.Deproject(intersection.Value.inters, line1);
                                Point3D point2 = this.Deproject(intersection.Value.inters, line2);

                                double dist1 = this.ZDepth(point1);
                                double dist2 = this.ZDepth(point2);

                                if (Math.Abs(dist1 - dist2) < Camera.Tolerance)
                                {
                                    return(0);
                                }

                                return(-Math.Sign(dist1 - dist2));
                            }
                            catch
                            {
                                return(0);
                            }
                        }
                        else
                        {
                            return(0);
                        }
                    }
                    else
                    {
                        return(0);
                    }
                }
                else if (element2 is Triangle3DElement triangle)
                {
                    Point l11 = this.Project(line1[0]);
                    Point l12 = this.Project(line1[1]);

                    Point lineDirPerp = new Point(l12.Y - l11.Y, l11.X - l12.X);
                    lineDirPerp = new Point(lineDirPerp.X / lineDirPerp.Modulus(), lineDirPerp.Y / lineDirPerp.Modulus());

                    Point l21 = new Point(l11.X + lineDirPerp.X * line1.Thickness * 0.5, l11.Y + lineDirPerp.Y * line1.Thickness * 0.5);
                    Point l22 = new Point(l12.X + lineDirPerp.X * line1.Thickness * 0.5, l12.Y + lineDirPerp.Y * line1.Thickness * 0.5);

                    Point l31 = new Point(l11.X - lineDirPerp.X * line1.Thickness * 0.5, l11.Y - lineDirPerp.Y * line1.Thickness * 0.5);
                    Point l32 = new Point(l12.X - lineDirPerp.X * line1.Thickness * 0.5, l12.Y - lineDirPerp.Y * line1.Thickness * 0.5);


                    Point A = this.Project(triangle[0]);
                    Point B = this.Project(triangle[1]);
                    Point C = this.Project(triangle[2]);

                    List <Point> interss1 = Intersections2D.Intersect(l11, l12, A, B, C, line1.Thickness, Camera.Tolerance);
                    List <Point> interss2 = Intersections2D.Intersect(l21, l22, A, B, C, Camera.Tolerance);
                    List <Point> interss3 = Intersections2D.Intersect(l31, l32, A, B, C, Camera.Tolerance);

                    List <Point> interss = new List <Point>();

                    if (interss1 != null && interss1.Count > 0)
                    {
                        interss.AddRange(interss1);
                    }

                    if (interss2 != null && interss2.Count > 0)
                    {
                        interss.AddRange(from el in interss2 select Intersections2D.ProjectOnLine(el, l11, l12));
                    }

                    if (interss3 != null && interss3.Count > 0)
                    {
                        interss.AddRange(from el in interss3 select Intersections2D.ProjectOnLine(el, l11, l12));
                    }

                    if (interss != null && interss.Count > 0)
                    {
                        int sign = 0;

                        foreach (Point pt in interss)
                        {
                            try
                            {
                                Point3D pt3D1 = this.Deproject(pt, line1);
                                Point3D pt3D2 = this.Deproject(pt, triangle);

                                double dist1 = this.ZDepth(pt3D1);
                                double dist2 = this.ZDepth(pt3D2);

                                int currSign = -Math.Sign(dist1 - dist2);

                                if (Math.Abs(dist1 - dist2) < Camera.Tolerance)
                                {
                                    currSign = 0;
                                }

                                if (sign == 0 || currSign == sign || currSign == 0)
                                {
                                    sign = currSign;
                                }
                                else
                                {
                                    //Line intersects with triangle
                                    return(0);
                                }
                            }
                            catch { }
                        }

                        return(sign);
                    }
                    else
                    {
                        return(0);
                    }
                }
                else
                {
                    throw new NotImplementedException();
                }
            }
            else if (element1 is Triangle3DElement triangle1)
            {
                if (element2 is Point3DElement || element2 is Line3DElement)
                {
                    return(-Compare(element2, element1));
                }
                else if (element2 is Triangle3DElement triangle2)
                {
                    Point[] triangle1Projection = triangle1.GetProjection();
                    Point[] triangle2Projection = triangle2.GetProjection();

                    Point A1 = triangle1Projection[0];
                    Point B1 = triangle1Projection[1];
                    Point C1 = triangle1Projection[2];

                    Point A2 = triangle2Projection[0];
                    Point B2 = triangle2Projection[1];
                    Point C2 = triangle2Projection[2];

                    List <Point> intersections = Intersections2D.IntersectTriangles(A1, B1, C1, A2, B2, C2, Camera.Tolerance);

                    if (intersections.Count >= 3)
                    {
                        double meanX = 0;
                        double meanY = 0;

                        foreach (Point p in intersections)
                        {
                            meanX += p.X;
                            meanY += p.Y;
                        }

                        meanX /= intersections.Count;
                        meanY /= intersections.Count;

                        Point pt = new Point(meanX, meanY);

                        try
                        {
                            Point3D pt3D1 = this.Deproject(pt, triangle1);
                            Point3D pt3D2 = this.Deproject(pt, triangle2);

                            double dist1 = this.ZDepth(pt3D1);
                            double dist2 = this.ZDepth(pt3D2);

                            if (double.IsNaN(dist1 - dist2))
                            {
                                return(0);
                            }


                            int sign = -Math.Sign(dist1 - dist2);

                            if (Math.Abs(dist1 - dist2) < Camera.Tolerance)
                            {
                                sign = 0;
                            }


                            return(sign);
                        }
                        catch { return(0); }
                    }
                    else
                    {
                        return(0);
                    }
                }
                else
                {
                    throw new NotImplementedException();
                }
            }
            else
            {
                throw new NotImplementedException();
            }
        }
Ejemplo n.º 8
0
        public static List <Point> Intersect(Point l11, Point l12, Point A, Point B, Point C, double lineThickness, double tolerance)
        {
            double lineLength = new Point(l11.X - l12.X, l11.Y - l12.Y).Modulus();

            double AB = new Point(A.X - B.X, A.Y - B.Y).Modulus();
            double BC = new Point(B.X - C.X, B.Y - C.Y).Modulus();
            double CA = new Point(C.X - A.X, C.Y - A.Y).Modulus();

            (Point inters, double t, double s)? intersAB = Intersections2D.Intersect(l11, l12, A, B);
            (Point inters, double t, double s)? intersBC = Intersections2D.Intersect(l11, l12, B, C);
            (Point inters, double t, double s)? intersCA = Intersections2D.Intersect(l11, l12, C, A);

            bool ABtrue = intersAB != null && intersAB.Value.s >= -tolerance && intersAB.Value.s <= AB + tolerance;
            bool BCtrue = intersBC != null && intersBC.Value.s >= -tolerance && intersBC.Value.s <= BC + tolerance;
            bool CAtrue = intersCA != null && intersCA.Value.s >= -tolerance && intersCA.Value.s <= CA + tolerance;

            List <Point> intersections = new List <Point>(3);

            if (ABtrue)
            {
                Point inters;

                if (intersAB.Value.t >= -lineThickness && intersAB.Value.t <= lineLength + lineThickness)
                {
                    inters = intersAB.Value.inters;
                }
                else if (intersAB.Value.t < -lineThickness)
                {
                    inters = l11;
                }
                else
                {
                    inters = l12;
                }

                bool found = false;

                foreach (Point pt in intersections)
                {
                    if (AreEqual(pt, inters, tolerance))
                    {
                        found = true;
                        break;
                    }
                }

                if (!found)
                {
                    intersections.Add(inters);
                }
            }

            if (BCtrue)
            {
                Point inters;

                if (intersBC.Value.t >= -lineThickness && intersBC.Value.t <= lineLength + lineThickness)
                {
                    inters = intersBC.Value.inters;
                }
                else if (intersBC.Value.t < -lineThickness)
                {
                    inters = l11;
                }
                else
                {
                    inters = l12;
                }

                bool found = false;

                foreach (Point pt in intersections)
                {
                    if (AreEqual(pt, inters, tolerance))
                    {
                        found = true;
                        break;
                    }
                }

                if (!found)
                {
                    intersections.Add(inters);
                }
            }

            if (CAtrue)
            {
                Point inters;

                if (intersCA.Value.t >= -lineThickness && intersCA.Value.t <= lineLength + lineThickness)
                {
                    inters = intersCA.Value.inters;
                }
                else if (intersCA.Value.t < -lineThickness)
                {
                    inters = l11;
                }
                else
                {
                    inters = l12;
                }

                bool found = false;

                foreach (Point pt in intersections)
                {
                    if (AreEqual(pt, inters, tolerance))
                    {
                        found = true;
                        break;
                    }
                }

                if (!found)
                {
                    intersections.Add(inters);
                }
            }



            return(intersections);
        }