예제 #1
0
        /// <inheritdoc/>
        public override bool IsCulled(Element3D element)
        {
            if (element is Point3DElement)
            {
                return((element[0] - this.Position) * this.Direction < 0);
            }
            else if (element is Line3DElement)
            {
                foreach (Point3D pt in element)
                {
                    if ((pt - this.Position) * this.Direction > 0)
                    {
                        return(false);
                    }
                }
                return(true);
            }
            else if (element is Triangle3DElement triangle)
            {
                bool found = false;

                foreach (Point3D pt in element)
                {
                    if ((pt - this.Position) * this.Direction > 0)
                    {
                        found = true;
                    }
                }

                if (!found)
                {
                    return(true);
                }
                else
                {
                    return(triangle.ActualNormal * this.Direction < 0);
                }
            }
            else
            {
                return(true);
            }
        }
예제 #2
0
 /// <inheritdoc/>
 public void AddElement(Element3D element)
 {
     this.sceneElements.Add(element);
 }
예제 #3
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);
                }
            }
        }
예제 #4
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();
            }
        }
예제 #5
0
 /// <summary>
 /// Determines whether an object should be culled (i.e. hidden) when the scene is rendered using the current camera.
 /// </summary>
 /// <param name="element">The <see cref="Element3D"/> to test.</param>
 /// <returns>A boolean value indicating whether the element should be culled or not.</returns>
 public abstract bool IsCulled(Element3D element);