Beispiel #1
0
 /// <summary>
 /// Creates a new rotation transformation that aligns <paramref name="a"/> with <paramref name="b"/>.
 /// </summary>
 /// <param name="a">The vector that should be aligned with <paramref name="b"/>.</param>
 /// <param name="b">The reference vector.</param>
 /// <returns>A <see cref="Transform3D"/> such that applying this transform to <paramref name="a"/> returns <paramref name="b"/> and the determinant of the transformation is 1.</returns>
 public static Transform3D RotationToAlignAWithB(NormalizedVector3D a, NormalizedVector3D b)
 {
     double[,] matrix3x3 = Matrix3D.RotationToAlignAWithB(a, b);
     return(new Transform3D(new double[, ] {
         { matrix3x3[0, 0], matrix3x3[0, 1], matrix3x3[0, 2], 0 }, { matrix3x3[1, 0], matrix3x3[1, 1], matrix3x3[1, 2], 0 }, { matrix3x3[2, 0], matrix3x3[2, 1], matrix3x3[2, 2], 0 }, { 0, 0, 0, 1 }
     }));
 }
Beispiel #2
0
        /// <inheritdoc/>
        public Camera[] GetCameras()
        {
            if (this.LensWidth == 0 || this.SamplingPoints == 1)
            {
                return(new Camera[] { this });
            }
            else
            {
                NormalizedVector3D xAxis = (this.Direction ^ this.RotationReference).Normalize();

                Camera[] tbr = new Camera[this.SamplingPoints];

                for (int i = 0; i < this.SamplingPoints; i++)
                {
                    double r     = ((double)i / (this.SamplingPoints - 1)) * this.LensWidth;
                    double theta = (double)i / (this.SamplingPoints - 1) * 2 * Math.PI * (this.SamplingPoints / 3.7);

                    double x = r * Math.Cos(theta);
                    double y = r * Math.Sin(theta);

                    Point3D pt = this.Position + x * xAxis + y * this.RotationReference;
                    tbr[i] = new PerspectiveCamera(pt, this.Direction, this.Distance, this.Size, this.ScaleFactor, this.RotationReference, this.Origin);
                }

                return(tbr);
            }
        }
Beispiel #3
0
        /// <summary>
        /// Creates a new <see cref="MaskedLightSource"/> using the specified <paramref name="triangulatedMask"/>.
        /// </summary>
        /// <param name="intensity">The base intensity of the light.</param>
        /// <param name="position">The position of the light source.</param>
        /// <param name="direction">The direction of the light.</param>
        /// <param name="distance">The distance between the light source and the mask plane.</param>
        /// <param name="triangulatedMask">A collection of <see cref="GraphicsPath"/>s representing the transparent part of the mask. Each <see cref="GraphicsPath"/> should represent a single triangle.</param>
        /// <param name="maskOrientation">An angle in radians determining the orientation of the 2D mask in the mask plane.</param>
        public MaskedLightSource(double intensity, Point3D position, NormalizedVector3D direction, double distance, IEnumerable <GraphicsPath> triangulatedMask, double maskOrientation)
        {
            this.Intensity = intensity;
            this.Position  = position;
            this.Direction = direction;
            this.Distance  = distance;
            this.Origin    = this.Position + distance * this.Direction;

            double[,] rotation = Matrix3D.RotationToAlignWithZ(direction).Inverse();

            double[,] rotation2 = Matrix3D.RotationAroundAxis(direction, maskOrientation);

            List <Point3D[]> maskList = new List <Point3D[]>();

            foreach (GraphicsPath trianglePath in triangulatedMask)
            {
                Point3D[] triangle = new Point3D[3];

                List <Point> points = trianglePath.GetPoints().First();

                for (int i = 0; i < 3; i++)
                {
                    triangle[i] = (Point3D)((Vector3D)(rotation2 * (rotation * new Point3D(points[i].X, points[i].Y, 0))) + Origin);
                }

                maskList.Add(triangle);
            }

            this.TriangulatedMask = maskList;
        }
Beispiel #4
0
        /// <summary>
        /// Creates a new <see cref="OrthographicCamera"/> instance.
        /// </summary>
        /// <param name="position">The position of the centre of the camera plane.</param>
        /// <param name="direction">The direction towards which the camera is pointing.</param>
        /// <param name="viewSize">The size of the image produced by the camera.</param>
        /// <param name="scaleFactor">The scale factor used to convert camera plane units into 2D units.</param>
        public OrthographicCamera(Point3D position, NormalizedVector3D direction, Size viewSize, double scaleFactor)
        {
            this.Position  = position;
            this.Direction = direction;

            this.RotationMatrix = Matrix3D.RotationToAlignWithZ(direction);

            this.ScaleFactor = scaleFactor;

            this.TopLeft = new Point(-viewSize.Width * 0.5 * ScaleFactor, -viewSize.Height * 0.5 * ScaleFactor);
            this.Size    = new Size(viewSize.Width * ScaleFactor, viewSize.Height * ScaleFactor);

            this.OrbitOrigin = position + direction * ((Vector3D)position).Modulus;

            if (new Vector3D(0, 1, 0) * this.Direction < 1)
            {
                this.RotationReference = (new Vector3D(0, 1, 0) - (new Vector3D(0, 1, 0) * this.Direction) * this.Direction).Normalize();
            }
            else
            {
                this.RotationReference = (new Vector3D(0, 0, 1) - (new Vector3D(0, 0, 1) * this.Direction) * this.Direction).Normalize();
            }

            Point3D rotatedY      = this.RotationMatrix * (Point3D)(Vector3D)this.RotationReference;
            double  rotationAngle = Math.PI / 2 - Math.Atan2(rotatedY.Y, rotatedY.X);

            this.CameraRotationMatrix = Matrix3D.RotationAroundAxis(new NormalizedVector3D(0, 0, 1), rotationAngle);
        }
Beispiel #5
0
        private static (byte R, byte G, byte B, byte A) GetPixelColor(Triangle3DElement triangle, Point3D correspPoint, Camera camera, List <ILightSource> lights, List <double> obstructions)
        {
            NormalizedVector3D normal = triangle.GetNormalAt(correspPoint);

            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, normal, 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));
                }
            }

            return(R, G, B, A);
        }
Beispiel #6
0
        /// <inheritdoc/>
        public override void Orbit(double theta, double phi)
        {
            Vector3D vect = this.Position - this.OrbitOrigin;

            NormalizedVector3D yAxis = new NormalizedVector3D(0, 1, 0);
            NormalizedVector3D xAxis = (this.Direction ^ (Vector3D)yAxis).Normalize();

            phi   *= Math.Sign(Math.Atan2(xAxis.Z, xAxis.X));
            theta *= Math.Sign(yAxis * this.RotationReference);

            double[,] thetaRotation = Matrix3D.RotationAroundAxis(yAxis, theta);

            double[,] phiRotation = Matrix3D.RotationAroundAxis(xAxis, phi);

            Vector3D rotatedVect = (Vector3D)(phiRotation * (thetaRotation * (Point3D)vect));

            this.Position          = this.OrbitOrigin + rotatedVect;
            this.Direction         = (this.OrbitOrigin - this.Position).Normalize();
            this.RotationReference = ((Vector3D)(phiRotation * (thetaRotation * (Point3D)(Vector3D)this.RotationReference))).Normalize();
            this.RotationMatrix    = Matrix3D.RotationToAlignWithZ(this.Direction);

            Point3D rotatedY      = this.RotationMatrix * (Point3D)(Vector3D)this.RotationReference;
            double  rotationAngle = Math.PI / 2 - Math.Atan2(rotatedY.Y, rotatedY.X);

            this.CameraRotationMatrix = Matrix3D.RotationAroundAxis(new NormalizedVector3D(0, 0, 1), rotationAngle);
        }
Beispiel #7
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);
        }
Beispiel #8
0
        public static double[,] RotationToAlignAWithB(NormalizedVector3D a, NormalizedVector3D b)
        {
            double c = a * b;

            if (c != -1)
            {
                Vector3D v = a ^ b;

                c = 1 / (1 + c);

                return(new double[3, 3]
                {
                    { 1 - (v.Y * v.Y - v.Z * v.Z) * c, (v.X * v.Y) * c - v.Z, (v.X * v.Z) * c + v.Y },
                    { (v.X * v.Y) * c + v.Z, 1 + (-v.X * v.X - v.Z * v.Z) * c, (v.Y * v.Z) * c - v.X },
                    { (v.X * v.Z) * c - v.Y, (v.Y * v.Z) * c + v.X, 1 + (-v.X * v.X - v.Y * v.Y) * c }
                });
            }
            else
            {
                if (a.X != 0 || a.Z != 0)
                {
                    NormalizedVector3D p = new NormalizedVector3D(-a.Z, 0, a.X);

                    return(RotationAroundAxis(p, Math.PI));
                }
                else //a.Y != 0
                {
                    NormalizedVector3D p = new NormalizedVector3D(0, a.Z, -a.Y);

                    return(RotationAroundAxis(p, Math.PI));
                }
            }
        }
Beispiel #9
0
 /// <summary>
 /// Creates a new transformation corresponding to a rotation around a specified axis.
 /// </summary>
 /// <param name="axis">The axis around which to rotate.</param>
 /// <param name="theta">The rotation angle in radians.</param>
 /// <returns>A <see cref="Transform3D"/> corresponding to the specified rotation.</returns>
 public static Transform3D RotationAlongAxis(NormalizedVector3D axis, double theta)
 {
     double[,] matrix3x3 = Matrix3D.RotationAroundAxis(axis, theta);
     return(new Transform3D(new double[, ] {
         { matrix3x3[0, 0], matrix3x3[0, 1], matrix3x3[0, 2], 0 }, { matrix3x3[1, 0], matrix3x3[1, 1], matrix3x3[1, 2], 0 }, { matrix3x3[2, 0], matrix3x3[2, 1], matrix3x3[2, 2], 0 }, { 0, 0, 0, 1 }
     }));
 }
Beispiel #10
0
 /// <summary>
 /// Creates a new <see cref="SpotlightLightSource"/> instance.
 /// </summary>
 /// <param name="intensity">The intensity of the light.</param>
 /// <param name="position">The position of the light source.</param>
 /// <param name="direction">The direction of the cone's axis.</param>
 /// <param name="beamWidthAngle">The angular size of the light cone, in radians.</param>
 /// <param name="cutoffAngle">The angular size of the cutoff cone, in radians.</param>
 public SpotlightLightSource(double intensity, Point3D position, NormalizedVector3D direction, double beamWidthAngle, double cutoffAngle)
 {
     this.Position       = position;
     this.Direction      = direction;
     this.Intensity      = intensity;
     this.BeamWidthAngle = beamWidthAngle;
     this.CutoffAngle    = cutoffAngle;
 }
Beispiel #11
0
        public static double[,] RotationAroundAxis(NormalizedVector3D axis, double theta)
        {
            double cos = Math.Cos(theta);
            double sin = Math.Sin(theta);

            return(new double[3, 3]
            {
                { cos + axis.X * axis.X * (1 - cos), axis.X *axis.Y *(1 - cos) - axis.Z * sin, axis.X *axis.Z *(1 - cos) + axis.Y * sin },
                { axis.Y *axis.X *(1 - cos) + axis.Z * sin, cos + axis.Y * axis.Y * (1 - cos), axis.Y *axis.Z *(1 - cos) - axis.X * sin },
                { axis.Z *axis.X *(1 - cos) - axis.Y * sin, axis.Z *axis.Y *(1 - cos) + axis.X * sin, cos + axis.Z * axis.Z * (1 - cos) }
            });
        }
Beispiel #12
0
        /// <summary>
        /// Creates a new <see cref="AreaLightSource"/> instance.
        /// </summary>
        /// <param name="intensity">The base intensity of the light.</param>
        /// <param name="center">The centre of the light-emitting area.</param>
        /// <param name="radius">The radius of the light-emitting area.</param>
        /// <param name="penumbraRadius">The radius of the penumbra area.</param>
        /// <param name="direction">The direction of the light.</param>
        /// <param name="sourceDistance">The distance between the focal point of the light and the light's center.</param>
        /// <param name="shadowSamplingPointCount">The number of points to use when determining the amount of light that is obstructed at a certain point.</param>
        public AreaLightSource(double intensity, Point3D center, double radius, double penumbraRadius, NormalizedVector3D direction, double sourceDistance, int shadowSamplingPointCount)
        {
            if (shadowSamplingPointCount < 1)
            {
                throw new ArgumentOutOfRangeException(nameof(shadowSamplingPointCount), shadowSamplingPointCount, "The number of shadow sampling points must be greater than or equal to 1!");
            }

            this.Center         = center;
            this.Direction      = direction;
            this.Intensity      = intensity;
            this.Radius         = radius;
            this.PenumbraRadius = penumbraRadius;
            this.SourceDistance = sourceDistance;

            this.VirtualSource = this.Center - this.Direction * this.SourceDistance;

            this.ShadowSamplingPointCount = shadowSamplingPointCount;

            NormalizedVector3D yAxis;

            if (Math.Abs(new Vector3D(0, 1, 0) * this.Direction) < 1)
            {
                yAxis = (new Vector3D(0, 1, 0) - (new Vector3D(0, 1, 0) * this.Direction) * this.Direction).Normalize();
            }
            else
            {
                yAxis = (new Vector3D(0, 0, 1) - (new Vector3D(0, 0, 1) * this.Direction) * this.Direction).Normalize();
            }

            NormalizedVector3D xAxis = (this.Direction ^ yAxis).Normalize();

            this.ShadowSamplingPoints = new Point3D[shadowSamplingPointCount - 1];

            for (int i = 0; i < shadowSamplingPointCount - 1; i++)
            {
                double r     = ((double)i / (shadowSamplingPointCount - 2)) * this.Radius;
                double theta = (double)i / (shadowSamplingPointCount - 2) * 2 * Math.PI * ((shadowSamplingPointCount - 1) / 3.7);

                double x = r * Math.Cos(theta);
                double y = r * Math.Sin(theta);

                Point3D pt = this.Center + x * xAxis + y * yAxis;
                this.ShadowSamplingPoints[i] = pt;
            }
        }
Beispiel #13
0
        /// <inheritdoc/>
        public double GetObstruction(Point3D point, IEnumerable <Triangle3DElement> shadowingTriangles)
        {
            Vector3D           reverseDir     = this.Position - point;
            double             maxD           = reverseDir.Modulus;
            NormalizedVector3D reverseDirNorm = new NormalizedVector3D(reverseDir.X / maxD, reverseDir.Y / maxD, reverseDir.Z / maxD, false);

            foreach (Triangle3DElement triangle in shadowingTriangles)
            {
                Point3D?projected = triangle.ProjectOnThisPlane(point, reverseDirNorm, true, maxD);

                if (projected != null && Intersections3D.PointInTriangle(projected.Value, triangle.Point1, triangle.Point2, triangle.Point3))
                {
                    return(1);
                }
            }

            return(0);
        }
Beispiel #14
0
        private static (byte R, byte G, byte B, byte A) GetPixelColorWithShadow(Triangle3DElement triangle, List <ILightSource> lights, IEnumerable <Triangle3DElement> shadowers, Point3D correspPoint, Camera camera)
        {
            List <double> pixelObstructions = new List <double>(lights.Count);

            for (int i = 0; i < lights.Count; i++)
            {
                if (!lights[i].CastsShadow)
                {
                    pixelObstructions.Add(0);
                }
                else
                {
                    pixelObstructions.Add(lights[i].GetObstruction(correspPoint, from el in shadowers where el != triangle select el));
                }
            }


            byte R = 0;
            byte G = 0;
            byte B = 0;
            byte A = 0;

            NormalizedVector3D normal = triangle.GetNormalAt(correspPoint);

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

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

            return(R, G, B, A);
        }
Beispiel #15
0
        /// <summary>
        /// Applies the transformation to a <see cref="Triangle3DElement"/>.
        /// </summary>
        /// <param name="triangle">The <see cref="Triangle3DElement"/> to which the transformation should be applied.</param>
        /// <returns>A <see cref="Triangle3DElement"/> corresponding to a triangle in which the transformation has been applied to the points from <paramref name="triangle" />. Properties are preserved between the two elements.</returns>
        public Triangle3DElement Apply(Triangle3DElement triangle)
        {
            Point3D p1 = this.Apply(triangle.Point1);
            Point3D p2 = this.Apply(triangle.Point2);
            Point3D p3 = this.Apply(triangle.Point3);

            if (!triangle.IsFlat)
            {
                Point3D p1Ref = triangle.Point1 + (Vector3D)triangle.Point1Normal;
                Point3D p2Ref = triangle.Point2 + (Vector3D)triangle.Point2Normal;
                Point3D p3Ref = triangle.Point3 + (Vector3D)triangle.Point3Normal;

                p1Ref = this.Apply(p1Ref);
                p2Ref = this.Apply(p2Ref);
                p3Ref = this.Apply(p3Ref);

                NormalizedVector3D n1 = (p1Ref - p1).Normalize();
                NormalizedVector3D n2 = (p2Ref - p2).Normalize();
                NormalizedVector3D n3 = (p3Ref - p3).Normalize();

                Triangle3DElement tbr = new Triangle3DElement(p1, p2, p3, n1, n2, n3)
                {
                    CastsShadow = triangle.CastsShadow, ReceivesShadow = triangle.ReceivesShadow, Tag = triangle.Tag, ZIndex = triangle.ZIndex
                };

                tbr.Fill.AddRange(triangle.Fill);

                return(tbr);
            }
            else
            {
                Triangle3DElement tbr = new Triangle3DElement(p1, p2, p3)
                {
                    CastsShadow = triangle.CastsShadow, ReceivesShadow = triangle.ReceivesShadow, Tag = triangle.Tag, ZIndex = triangle.ZIndex
                };

                tbr.Fill.AddRange(triangle.Fill);

                return(tbr);
            }
        }
Beispiel #16
0
        public static double[,] RotationToAlignWithZ(NormalizedVector3D vector, bool preferY = true)
        {
            if (vector.Z != -1)
            {
                Vector3D v = new Vector3D(vector.Y, -vector.X, 0);
                double   c = 1 / (1 + vector.Z);

                return(new double[3, 3]
                {
                    { 1 - v.Y * v.Y * c, v.X *v.Y *c, v.Y },
                    { v.X *v.Y *c, 1 - v.X *v.X *c, -v.X },
                    { -v.Y, v.X, 1 - v.X * v.X * c - v.Y * v.Y * c }
                });
            }
            else
            {
                if (!preferY)
                {
                    return(new double[3, 3]
                    {
                        { 1, 0, 0 },
                        { 0, -1, 0 },
                        { 0, 0, -1 }
                    });
                }
                else
                {
                    return(new double[3, 3]
                    {
                        { -1, 0, 0 },
                        { 0, 1, 0 },
                        { 0, 0, -1 }
                    });
                }
            }
        }
Beispiel #17
0
        private PerspectiveCamera(Point3D position, NormalizedVector3D direction, double distance, Size viewSize, double scaleFactor, NormalizedVector3D rotationReference, Point3D origin2DReference)
        {
            this.Position  = position;
            this.Direction = direction;
            this.Distance  = distance;

            this.Origin2DReference = origin2DReference;
            this.Origin            = position + direction * distance;
            this.RotationMatrix    = Matrix3D.RotationToAlignWithZ(direction);

            this.ScaleFactor = scaleFactor;

            this.TopLeft = new Point(-viewSize.Width * 0.5 * ScaleFactor, -viewSize.Height * 0.5 * ScaleFactor);
            this.Size    = new Size(viewSize.Width * ScaleFactor, viewSize.Height * ScaleFactor);

            this.OrbitOrigin = position + direction * ((Vector3D)position).Modulus;

            this.RotationReference = rotationReference;

            Point3D rotatedY      = this.RotationMatrix * (Point3D)(Vector3D)this.RotationReference;
            double  rotationAngle = Math.PI / 2 - Math.Atan2(rotatedY.Y, rotatedY.X);

            this.CameraRotationMatrix = Matrix3D.RotationAroundAxis(new NormalizedVector3D(0, 0, 1), rotationAngle);
        }
Beispiel #18
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);
                }
            }
        }
Beispiel #19
0
        /// <inheritdoc/>
        public double GetObstruction(Point3D point, IEnumerable <Triangle3DElement> shadowingTriangles)
        {
            double totalObstruction = 0;
            int    sampleCount      = 0;

            {
                Vector3D reverseDir = this.VirtualSource - point;

                double denom = (reverseDir * this.Direction);

                if (denom == 0)
                {
                    //totalObstruction += 0;
                    sampleCount++;
                }
                else
                {
                    double  d  = this.SourceDistance / denom;
                    Point3D pt = this.VirtualSource + d * reverseDir;

                    double             maxD           = (point - pt).Modulus;
                    NormalizedVector3D reverseDirNorm = new NormalizedVector3D(reverseDir.X / maxD, reverseDir.Y / maxD, reverseDir.Z / maxD, false);

                    bool found = false;

                    foreach (Triangle3DElement triangle in shadowingTriangles)
                    {
                        Point3D?projected = triangle.ProjectOnThisPlane(point, reverseDirNorm, true, maxD);

                        if (projected != null && Intersections3D.PointInTriangle(projected.Value, triangle.Point1, triangle.Point2, triangle.Point3))
                        {
                            totalObstruction += 1;
                            sampleCount++;
                            found = true;
                            break;
                        }
                    }

                    if (!found)
                    {
                        //totalObstruction += 0;
                        sampleCount++;
                    }
                }
            }


            for (int i = 0; i < ShadowSamplingPoints.Length; i++)
            {
                Vector3D reverseDir = ShadowSamplingPoints[i] - point;

                double             maxD           = reverseDir.Modulus;
                NormalizedVector3D reverseDirNorm = new NormalizedVector3D(reverseDir.X / maxD, reverseDir.Y / maxD, reverseDir.Z / maxD, false);

                bool found = false;

                foreach (Triangle3DElement triangle in shadowingTriangles)
                {
                    Point3D?projected = triangle.ProjectOnThisPlane(point, reverseDirNorm, true, maxD);

                    if (projected != null && Intersections3D.PointInTriangle(projected.Value, triangle.Point1, triangle.Point2, triangle.Point3))
                    {
                        totalObstruction += 1;
                        sampleCount++;
                        found = true;
                        break;
                    }
                }

                if (!found)
                {
                    //totalObstruction += 0;
                    sampleCount++;
                }
            }

            return(totalObstruction / sampleCount);
        }
Beispiel #20
0
        /// <summary>
        /// Creates a quadrilater, specifying the vertex normals at the four vertices. All the vertices need not be coplanar.
        /// </summary>
        /// <param name="point1">The first vertex of the quadrilater.</param>
        /// <param name="point2">The second vertex of the quadrilater.</param>
        /// <param name="point3">The third vertex of the quadrilater.</param>
        /// <param name="point4">The fourth vertex of the quadrilater.</param>
        /// <param name="point1Normal">The vertex normal at the first vertex of the quadrilater.</param>
        /// <param name="point2Normal">The vertex normal at the second vertex of the quadrilater.</param>
        /// <param name="point3Normal">The vertex normal at the third vertex of the quadrilater.</param>
        /// <param name="point4Normal">The vertex normal at the fourth vertex of the quadrilater.</param>
        /// <param name="fill">A collection of materials that will be applied to the <see cref="Triangle3DElement"/>s returned by this method.</param>
        /// <param name="tag">A tag that will be applied to the <see cref="Triangle3DElement"/>s returned by this method.</param>
        /// <param name="zIndex">A z-index that will be applied to the <see cref="Triangle3DElement"/>s returned by this method.</param>
        /// <returns>A list containing two <see cref="Triangle3DElement"/>s representing the quadrilater.</returns>
        public static List <Element3D> CreateRectangle(Point3D point1, Point3D point2, Point3D point3, Point3D point4, NormalizedVector3D point1Normal, NormalizedVector3D point2Normal, NormalizedVector3D point3Normal, NormalizedVector3D point4Normal, IEnumerable <IMaterial> fill, string tag = null, int zIndex = 0)
        {
            Triangle3DElement triangle1 = new Triangle3DElement(point1, point2, point3, point1Normal, point2Normal, point3Normal);

            triangle1.Fill.AddRange(fill);
            triangle1.Tag    = tag;
            triangle1.ZIndex = zIndex;

            Triangle3DElement triangle2 = new Triangle3DElement(point1, point3, point4, point1Normal, point3Normal, point4Normal);

            triangle2.Fill.AddRange(fill);
            triangle2.Tag    = tag;
            triangle2.ZIndex = zIndex;

            return(new List <Element3D> {
                triangle1, triangle2
            });
        }
Beispiel #21
0
 /// <inheritdoc/>
 public VectorRendererTriangle3DElement(Point3D point1, Point3D point2, Point3D point3, NormalizedVector3D point1Normal, NormalizedVector3D point2Normal, NormalizedVector3D point3Normal) : base(point1, point2, point3, point1Normal, point2Normal, point3Normal)
 {
 }
Beispiel #22
0
 /// <summary>
 /// Deconstructs the struct.
 /// </summary>
 /// <param name="intensity">This parameter will hold the <see cref="Intensity"/> of the light.</param>
 /// <param name="direction">This parameter will hold the <see cref="Direction"/> of the light.</param>
 public void Deconstruct(out double intensity, out NormalizedVector3D direction)
 {
     intensity = this.Intensity;
     direction = this.Direction;
 }
Beispiel #23
0
 /// <summary>
 /// Creates a new <see cref="MaskedLightSource"/> by triangulating the specified <see cref="GraphicsPath"/>.
 /// </summary>
 /// <param name="intensity">The base intensity of the light.</param>
 /// <param name="position">The position of the light source.</param>
 /// <param name="direction">The direction of the light.</param>
 /// <param name="distance">The distance between the light source and the mask plane.</param>
 /// <param name="mask">A <see cref="GraphicsPath"/> representing the transparent part of the mask.</param>
 /// <param name="maskOrientation">An angle in radians determining the orientation of the 2D mask in the mask plane.</param>
 /// <param name="triangulationResolution">The resolution to use to triangulate the <paramref name="mask"/>.</param>
 public MaskedLightSource(double intensity, Point3D position, NormalizedVector3D direction, double distance, GraphicsPath mask, double maskOrientation, double triangulationResolution) : this(intensity, position, direction, distance, mask.Triangulate(triangulationResolution, true), maskOrientation)
 {
 }
Beispiel #24
0
        /// <summary>
        /// Creates a flat polygon.
        /// </summary>
        /// <param name="polygon2D">A 2D <see cref="GraphicsPath"/> representing the polygon.</param>
        /// <param name="triangulationResolution">The resolution that will be used to linearise curve segments in the <see cref="GraphicsPath"/>.</param>
        /// <param name="origin">A <see cref="Point3D"/> that will correspond to the origin of the 2D reference system.</param>
        /// <param name="xAxis">A <see cref="NormalizedVector3D"/> that will correspond to the x axis of the 2D reference system. This will be orthonormalised to the <paramref name="yAxis"/>.</param>
        /// <param name="yAxis">A <see cref="NormalizedVector3D"/> that will correspond to the y axis of the 2D reference system.</param>
        /// <param name="reverseTriangles">Indicates whether the order of the points (and thus the normals) of all the triangles returned by this method should be reversed.</param>
        /// <param name="fill">A collection of materials that will be applied to the <see cref="Triangle3DElement"/>s returned by this method.</param>
        /// <param name="tag">A tag that will be applied to the <see cref="Triangle3DElement"/>s returned by this method.</param>
        /// <param name="zIndex">A z-index that will be applied to the <see cref="Triangle3DElement"/>s returned by this method.</param>
        /// <returns>A list of <see cref="Triangle3DElement"/>s that constitute the polygon.</returns>
        public static List <Element3D> CreatePolygon(GraphicsPath polygon2D, double triangulationResolution, Point3D origin, NormalizedVector3D xAxis, NormalizedVector3D yAxis, bool reverseTriangles, IEnumerable <IMaterial> fill, string tag = null, int zIndex = 0)
        {
            xAxis = (xAxis - yAxis * (xAxis * yAxis)).Normalize();

            List <GraphicsPath> triangles = polygon2D.Triangulate(triangulationResolution, true).ToList();

            List <Element3D> tbr = new List <Element3D>(triangles.Count);

            for (int i = 0; i < triangles.Count; i++)
            {
                Point p1 = triangles[i].Segments[0].Point;
                Point p2 = triangles[i].Segments[1].Point;
                Point p3 = triangles[i].Segments[2].Point;

                Point3D p13D = origin + xAxis * p1.X + yAxis * p1.Y;
                Point3D p23D = origin + xAxis * p2.X + yAxis * p2.Y;
                Point3D p33D = origin + xAxis * p3.X + yAxis * p3.Y;

                Triangle3DElement t = !reverseTriangles ? new Triangle3DElement(p13D, p23D, p33D) : new Triangle3DElement(p13D, p33D, p23D);
                t.Fill.AddRange(fill);
                t.Tag    = tag;
                t.ZIndex = zIndex;
                tbr.Add(t);
            }

            return(tbr);
        }
Beispiel #25
0
 /// <summary>
 /// Creates a new <see cref="LightIntensity"/>.
 /// </summary>
 /// <param name="intensity">The intensity of the light.</param>
 /// <param name="direction">The direction from which the light comes.</param>
 public LightIntensity(double intensity, NormalizedVector3D direction)
 {
     this.Intensity = intensity;
     this.Direction = direction;
 }
Beispiel #26
0
 /// <summary>
 /// Creates a new <see cref="ParallelLightSource"/> instance.
 /// </summary>
 /// <param name="intensity">The intensity of the light.</param>
 /// <param name="direction">The direction along which the light travels.</param>
 public ParallelLightSource(double intensity, NormalizedVector3D direction)
 {
     this.Intensity        = intensity;
     this.Direction        = direction;
     this.ReverseDirection = direction.Reverse();
 }
Beispiel #27
0
 /// <inheritdoc/>
 public Colour GetColour(Point3D point, NormalizedVector3D surfaceNormal, Camera camera, IList <ILightSource> lights, IList <double> obstructions)
 {
     return(Colour);
 }
Beispiel #28
0
        /// <summary>
        /// Creates a prism with the specified base.
        /// </summary>
        /// <param name="polygonBase2D">A 2D <see cref="GraphicsPath"/> representing the base of the prism.</param>
        /// <param name="triangulationResolution">The resolution that will be used to linearise curve segments in the <see cref="GraphicsPath"/>.</param>
        /// <param name="bottomOrigin">A <see cref="Point3D"/> that will correspond to the origin of the 2D reference system of the bottom base.</param>
        /// <param name="topOrigin">A <see cref="Point3D"/> that will correspond to the origin of the 2D reference system of the top base.</param>
        /// <param name="baseXAxis">A <see cref="NormalizedVector3D"/> that will correspond to the x axis of the 2D reference system of the bases. This will be orthonormalised to the <paramref name="baseYAxis"/>.</param>
        /// <param name="baseYAxis">A <see cref="NormalizedVector3D"/> that will correspond to the y axis of the 2D reference system of the bases.</param>
        /// <param name="fill">A collection of materials that will be applied to the <see cref="Triangle3DElement"/>s returned by this method.</param>
        /// <param name="tag">A tag that will be applied to the <see cref="Triangle3DElement"/>s returned by this method.</param>
        /// <param name="zIndex">A z-index that will be applied to the <see cref="Triangle3DElement"/>s returned by this method.</param>
        /// <returns>A list of <see cref="Triangle3DElement"/>s that constitute the prism.</returns>
        public static List <Element3D> CreatePrism(GraphicsPath polygonBase2D, double triangulationResolution, Point3D bottomOrigin, Point3D topOrigin, NormalizedVector3D baseXAxis, NormalizedVector3D baseYAxis, IEnumerable <IMaterial> fill, string tag = null, int zIndex = 0)
        {
            baseXAxis = (baseXAxis - baseYAxis * (baseXAxis * baseYAxis)).Normalize();

            List <Element3D> tbr = new List <Element3D>();

            bool orientation = (baseXAxis ^ baseYAxis) * (bottomOrigin - topOrigin) > 0;

            double[,] matrix1 = Matrix3D.RotationToAlignAWithB(new NormalizedVector3D(0, 1, 0), baseYAxis);
            double[,] matrix2 = Matrix3D.RotationToAlignAWithB(((Vector3D)(matrix1 * new Point3D(1, 0, 0))).Normalize(), baseXAxis);

            List <List <NormalizedVector3D> > normals = (from el2 in polygonBase2D.GetLinearisationPointsNormals(triangulationResolution) select(from el in el2 select(el.X * baseXAxis + el.Y * baseYAxis).Normalize()).ToList()).ToList();

            polygonBase2D = polygonBase2D.Linearise(triangulationResolution);

            tbr.AddRange(CreatePolygon(polygonBase2D, triangulationResolution, bottomOrigin, baseXAxis, baseYAxis, orientation, fill, tag, zIndex));
            tbr.AddRange(CreatePolygon(polygonBase2D, triangulationResolution, topOrigin, baseXAxis, baseYAxis, !orientation, fill, tag, zIndex));

            List <List <Point3D> > bottomPoints = (from el2 in polygonBase2D.GetPoints() select(from el in el2 select(Point3D)(el.X * baseXAxis + el.Y * baseYAxis + (Vector3D)bottomOrigin)).ToList()).ToList();
            List <List <Point3D> > topPoints    = (from el2 in polygonBase2D.GetPoints() select(from el in el2 select(Point3D)(el.X * baseXAxis + el.Y * baseYAxis + (Vector3D)topOrigin)).ToList()).ToList();

            if (orientation)
            {
                for (int i = 0; i < bottomPoints.Count; i++)
                {
                    for (int j = 0; j < bottomPoints[i].Count - 1; j++)
                    {
                        tbr.AddRange(CreateRectangle(bottomPoints[i][j], bottomPoints[i][j + 1], topPoints[i][j + 1], topPoints[i][j], normals[i][j], normals[i][j + 1], normals[i][j + 1], normals[i][j], fill, tag, zIndex));
                    }
                }
            }
            else
            {
                for (int i = 0; i < bottomPoints.Count; i++)
                {
                    for (int j = 0; j < bottomPoints[i].Count - 1; j++)
                    {
                        tbr.AddRange(CreateRectangle(bottomPoints[i][j], topPoints[i][j], topPoints[i][j + 1], bottomPoints[i][j + 1], normals[i][j], normals[i][j], normals[i][j + 1], normals[i][j + 1], fill, tag, zIndex));
                    }
                }
            }

            return(tbr);
        }