예제 #1
0
        /// <summary>
        /// Получение промежуточных точек линии. Интерполирование, можно сказать.
        /// </summary>
        /// <param name="p1">start point</param>
        /// <param name="p2">end point</param>
        /// <returns></returns>
        public static Point3D[] GetLine3DPoints(Point3D start, Point3D end)
        {
            var points = new List <Point3D>();

            double diffx = end.X - start.X;
            double diffy = end.Y - start.Y;

            if (Math.Abs(diffx) > Math.Abs(diffy)) // abs - убирание знака
            {
                // упорядочиваем точки по X
                if (diffx < 0)
                {
                    MathHelpers.Swap(ref start, ref end);
                }

                // получаем массив координат
                // их длина = |diffx|+1 (потому что рисуем отрезок, с начальной И конечной точкой.)
                double[] yCoords = MathHelpers.GetYsByXsBetweenTwoPoints2D(start.X, start.Y, end.X, end.Y);
                double[] zCoords = MathHelpers.GetYsByXsBetweenTwoPoints2D(start.X, start.Z, end.X, end.Z);

                // идем по X, получаем Y и Z
                for (double x = start.X; x <= end.X; ++x)
                {
                    //(x - start.X) и так будет int.
                    int    y = (int)yCoords[(int)(x - start.X)];
                    double z = zCoords[(int)(x - start.X)];

                    var point = new Point3D(x, y, z);
                    points.Add(point);
                }
            }
            else
            {
                // упорядочиваем точки по y
                if (diffy < 0)
                {
                    MathHelpers.Swap(ref start, ref end);
                }
                double[] xCoords = MathHelpers.GetYsByXsBetweenTwoPoints2D(start.Y, start.X, end.Y, end.X);
                double[] zCoords = MathHelpers.GetYsByXsBetweenTwoPoints2D(start.Y, start.Z, end.Y, end.Z);

                // идем по Y, получаем X и Z
                for (double y = start.Y; y <= end.Y; y++)
                {
                    int    x = (int)xCoords[(int)(y - start.Y)];
                    double z = zCoords[(int)(y - start.Y)];

                    var point = new Point3D(x, y, z);
                    points.Add(point);
                }
            }


            return(points.ToArray());
        }
예제 #2
0
        /// <summary>
        /// Draw line on the bitmap. Using z-buffer and color.
        /// </summary>
        private void DrawLine(FastBitmap bitmap, double[,] buffer, Point3D start, Point3D end, Color color)
        {
            // dx and dy are coord diffs between two points
            double diffx = end.X - start.X;
            double diffy = end.Y - start.Y;

            if (Math.Abs(diffx) > Math.Abs(diffy))
            {
                // I want to work with point1 is 'greater' than point2
                if (diffx < 0)
                {
                    MathHelpers.Swap(ref start, ref end);
                }
                // here we are getting the segment coordinates as an array of Double values
                double[] yCoords = MathHelpers.GetYsByXsBetweenTwoPoints2D(start.X, start.Y, end.X, end.Y);
                double[] zCoords = MathHelpers.GetYsByXsBetweenTwoPoints2D(start.X, start.Z, end.X, end.Z);

                // and here we draw the points
                for (double x = start.X; x <= end.X; ++x)
                {
                    int    y = (int)yCoords[(int)(x - start.X)];
                    double z = zCoords[(int)(x - start.X)];
                    if (IsWithinImage((int)x, y) && buffer[(int)x, y] >= z)
                    {
                        // in fact, there is smth like ray-tracing
                        // using z-buffer: if current point is closer to us than old one, we remember this...
                        buffer[(int)x, y] = z;
                        // and draw the point on the image. At last, the nearest point is drawing, other don't.
                        bitmap.SetPixel((int)x, y, color);
                    }
                }
            }
            else
            {
                // I want to work with point1 is 'greater' than point2
                if (diffy < 0)
                {
                    MathHelpers.Swap(ref start, ref end);
                }
                double[] xCoords = MathHelpers.GetYsByXsBetweenTwoPoints2D(start.Y, start.X, end.Y, end.X);
                double[] zCoords = MathHelpers.GetYsByXsBetweenTwoPoints2D(start.Y, start.Z, end.Y, end.Z);
                for (double y = start.Y; y <= end.Y; y++)
                {
                    int    x = (int)xCoords[(int)(y - start.Y)];
                    double z = zCoords[(int)(y - start.Y)];
                    if (IsWithinImage(x, (int)y) && buffer[x, (int)y] >= z)
                    {
                        buffer[x, (int)y] = z;
                        bitmap.SetPixel(x, (int)y, color);
                    }
                }
            }
        }
예제 #3
0
        /// <summary>
        /// Draws triangle on bitmap using specified point vectors and color (and z-buffer)
        /// </summary>
        private void DrawTriangle(Vector3D p0, Vector3D p1, Vector3D p2, Color color, FastBitmap bitmap, double[,] buffer)
        {
            if (p0.Y != p1.Y || p0.Y != p2.Y)
            {
                // упорядочение
                if (p0.Y > p1.Y)
                {
                    MathHelpers.Swap(ref p0, ref p1);
                }
                if (p0.Y > p2.Y)
                {
                    MathHelpers.Swap(ref p0, ref p2);
                }
                if (p1.Y > p2.Y)
                {
                    MathHelpers.Swap(ref p1, ref p2);
                }

                // in the next section, I turn the triangle into points, then draw them (using z-buffer): split the triangle into 2 segments (vertically), and rasterize them separately. The algorithm is described here: https://compgraphics.info/2D/triangle_rasterization.php
                int totalHeight = (int)Math.Round(p2.Y - p0.Y);
                for (int i = 0; i < totalHeight; ++i)
                {
                    bool     secondHalf    = i > p1.Y - p0.Y || p1.Y == p0.Y;
                    int      segmentHeight = (int)Math.Round(secondHalf ? p2.Y - p1.Y : p1.Y - p0.Y);
                    double   alpha         = (double)i / totalHeight;
                    double   beta          = (i - (secondHalf ? p1.Y - p0.Y : 0.0)) / segmentHeight;
                    Vector3D a             = p0 + (p2 - p0) * alpha;
                    Vector3D b             = (secondHalf ? p1 + (p2 - p1) * beta : p0 + (p1 - p0) * beta);

                    if (a.X > b.X)
                    { // I want first to be greater than second
                        MathHelpers.Swap(ref a, ref b);
                    }
                    for (int j = (int)Math.Round(a.X); j <= (int)Math.Round(b.X); ++j)
                    {
                        double   scale = (a.X == b.X) ? 1 : (j - a.X) / (b.X - a.X);
                        Vector3D p     = a + (b - a) * scale;
                        int      x     = (int)Math.Round(p.X);
                        int      y     = (int)Math.Round(p.Y);
                        if (IsWithinImage(x, y) && buffer[x, y] >= p.Z)
                        {
                            // z-buffer, we remember this new point
                            buffer[x, y] = p.Z;
                            bitmap.SetPixel(x, y, color);
                        }
                    }
                }
            }
        }