Example #1
0
            private unsafe void ProcessTearDropContourSplitAndColor(Contour contour, EdgeColor *colors)
            {
                var corner = _corners[0];
                var parts  = new EdgeSegment[] { null, null, null, null, null, null, null };

                contour[0].SplitInThirds(out parts[0 + 3 * corner], out parts[1 + 3 * corner],
                                         out parts[2 + 3 * corner]);
                if (contour.Count >= 2)
                {
                    contour[1].SplitInThirds(out parts[3 - 3 * corner],
                                             out parts[4 - 3 * corner],
                                             out parts[5 - 3 * corner]);
                    parts[0].Color = parts[1].Color = colors[0];
                    parts[2].Color = parts[3].Color = colors[1];
                    parts[4].Color = parts[5].Color = colors[2];
                }
                else
                {
                    parts[0].Color = colors[0];
                    parts[1].Color = colors[1];
                    parts[2].Color = colors[2];
                }

                contour.Clear();
                for (var i = 0; parts[i] != null; ++i)
                {
                    contour.Add(parts[i]);
                }
            }
Example #2
0
        internal EdgeBmpLut(List <ContourCorner> corners, List <EdgeSegment> flattenEdges, List <int> segOfNextContours, List <int> cornerOfNextContours)
        {
            //move first to last
            int startAt = 0;

            for (int i = 0; i < segOfNextContours.Count; ++i)
            {
                int nextStartAt = segOfNextContours[i];
                //
                EdgeSegment firstSegment = flattenEdges[startAt];

                flattenEdges.RemoveAt(startAt);
                if (i == segOfNextContours.Count - 1)
                {
                    flattenEdges.Add(firstSegment);
                }
                else
                {
                    flattenEdges.Insert(nextStartAt - 1, firstSegment);
                }
                startAt = nextStartAt;
            }

            _corners             = corners;
            _flattenEdges        = flattenEdges;
            EdgeOfNextContours   = segOfNextContours;
            CornerOfNextContours = cornerOfNextContours;
        }
Example #3
0
 public EdgeStructure(EdgeSegment[] edgeSegments, AreaKind areaKind)
 {
     _isEmpty      = false;
     _edgeSegment  = null;
     _edgeSegments = edgeSegments;
     _areaKind     = areaKind;
 }
Example #4
0
 public Vec2Info(EdgeSegment owner, Vec2PointKind kind, Vector2 point)
 {
     this.owner = owner;
     this.x     = point.x;
     this.y     = point.y;
     Kind       = kind;
 }
Example #5
0
        static void FlattenPoints(EdgeSegment segment, List <Vec2Info> points)
        {
            switch (segment.SegmentKind)
            {
            default: throw new NotSupportedException();

            case EdgeSegmentKind.LineSegment:
            {
                LinearSegment seg = (LinearSegment)segment;
                points.Add(new Vec2Info(segment, Vec2PointKind.Touch1, seg.P0));
            }
            break;

            case EdgeSegmentKind.QuadraticSegment:
            {
                QuadraticSegment seg = (QuadraticSegment)segment;
                points.Add(new Vec2Info(segment, Vec2PointKind.Touch1, seg.P0));
                points.Add(new Vec2Info(segment, Vec2PointKind.C2, seg.P1));
            }
            break;

            case EdgeSegmentKind.CubicSegment:
            {
                CubicSegment seg = (CubicSegment)segment;
                points.Add(new Vec2Info(segment, Vec2PointKind.Touch1, seg.P0));
                points.Add(new Vec2Info(segment, Vec2PointKind.C3, seg.P1));
                points.Add(new Vec2Info(segment, Vec2PointKind.C3, seg.P2));
            }
            break;
            }
        }
Example #6
0
 public EdgeStructure(EdgeSegment edgeSegment, AreaKind areaKind)
 {
     _isEmpty     = false;
     _edgeSegment = edgeSegment;
     _areaKind    = areaKind;
     //
     _edgeSegments = null;
 }
Example #7
0
 public override void SplitInThirds(out EdgeSegment part1, out EdgeSegment part2, out EdgeSegment part3)
 {
     part1 = new QuadraticSegment(Color, _p[0], Arithmetic.Mix(_p[0], _p[1], 1.0 / 3.0), Point(1.0 / 3.0));
     part2 = new QuadraticSegment(Color, Point(1.0 / 3.0),
                                  Arithmetic.Mix(Arithmetic.Mix(_p[0], _p[1], 5.0 / 9.0), Arithmetic.Mix(_p[1], _p[2], 4.0 / 9.0), 0.5),
                                  Point(2 / 3.0));
     part3 = new QuadraticSegment(Color, Point(2.0 / 3.0), Arithmetic.Mix(_p[1], _p[2], 2.0 / 3.0), _p[2]);
 }
 public override void splitInThirds(out EdgeSegment part1, out EdgeSegment part2, out EdgeSegment part3)
 {
     part1 = new CubicSegment(p[0], Vector2.IsEq(p[0], p[1]) ? p[0] : mix(p[0], p[1], 1 / 3.0), mix(mix(p[0], p[1], 1 / 3.0), mix(p[1], p[2], 1 / 3.0), 1 / 3.0), point(1 / 3.0), color);
     part2 = new CubicSegment(point(1 / 3.0),
                              mix(mix(mix(p[0], p[1], 1 / 3.0), mix(p[1], p[2], 1 / 3.0), 1 / 3.0), mix(mix(p[1], p[2], 1 / 3.0), mix(p[2], p[3], 1 / 3.0), 1 / 3.0), 2 / 3.0),
                              mix(mix(mix(p[0], p[1], 2 / 3.0), mix(p[1], p[2], 2 / 3.0), 2 / 3.0), mix(mix(p[1], p[2], 2 / 3.0), mix(p[2], p[3], 2 / 3.0), 2 / 3.0), 1 / 3.0),
                              point(2 / 3.0), color);
     part3 = new CubicSegment(point(2 / 3.0), mix(mix(p[1], p[2], 2 / 3.0), mix(p[2], p[3], 2 / 3.0), 2 / 3.0), Vector2.IsEq(p[2], p[3]) ? p[3] : mix(p[2], p[3], 2 / 3.0), p[3], color);
 }
Example #9
0
 public override void splitInThirds(out EdgeSegment part1, out EdgeSegment part2, out EdgeSegment part3)
 {
     part1 = new CubicSegment(_p0, Vector2.IsEq(_p0, _p1) ? _p0 : mix(_p0, _p1, 1 / 3.0), mix(mix(_p0, _p1, 1 / 3.0), mix(_p1, _p2, 1 / 3.0), 1 / 3.0), point(1 / 3.0), color);
     part2 = new CubicSegment(point(1 / 3.0),
                              mix(mix(mix(_p0, _p1, 1 / 3.0), mix(_p1, _p2, 1 / 3.0), 1 / 3.0), mix(mix(_p1, _p2, 1 / 3.0), mix(_p2, _p3, 1 / 3.0), 1 / 3.0), 2 / 3.0),
                              mix(mix(mix(_p0, _p1, 2 / 3.0), mix(_p1, _p2, 2 / 3.0), 2 / 3.0), mix(mix(_p1, _p2, 2 / 3.0), mix(_p2, _p3, 2 / 3.0), 2 / 3.0), 1 / 3.0),
                              point(2 / 3.0), color);
     part3 = new CubicSegment(point(2 / 3.0), mix(mix(_p1, _p2, 2 / 3.0), mix(_p2, _p3, 2 / 3.0), 2 / 3.0), Vector2.IsEq(_p2, _p3) ? _p3 : mix(_p2, _p3, 2 / 3.0), _p3, color);
 }
Example #10
0
 /// Normalizes the shape geometry for distance field generation.
 public void Normalize()
 {
     foreach (var contour in this)
     {
         if (contour.Count == 1)
         {
             var parts = new EdgeSegment[3];
             contour[0].SplitInThirds(out parts[0], out parts[1], out parts[2]);
             contour.Clear();
             contour.Add(parts[0]);
             contour.Add(parts[1]);
             contour.Add(parts[2]);
         }
     }
 }
Example #11
0
 public override void SplitInThirds(out EdgeSegment part1, out EdgeSegment part2, out EdgeSegment part3)
 {
     part1 = new CubicSegment(Color, _p[0], _p[0] == _p[1] ? _p[0] : Arithmetic.Mix(_p[0], _p[1], 1.0 / 3.0),
                              Arithmetic.Mix(Arithmetic.Mix(_p[0], _p[1], 1.0 / 3.0), Arithmetic.Mix(_p[1], _p[2], 1.0 / 3.0),
                                             1.0 / 3.0), Point(1.0 / 3.0));
     part2 = new CubicSegment(Color, Point(1.0 / 3.0),
                              Arithmetic.Mix(
                                  Arithmetic.Mix(Arithmetic.Mix(_p[0], _p[1], 1.0 / 3.0), Arithmetic.Mix(_p[1], _p[2], 1.0 / 3.0),
                                                 1.0 / 3.0),
                                  Arithmetic.Mix(Arithmetic.Mix(_p[1], _p[2], 1.0 / 3.0), Arithmetic.Mix(_p[2], _p[3], 1.0 / 3.0),
                                                 1.0 / 3.0), 2.0 / 3.0),
                              Arithmetic.Mix(
                                  Arithmetic.Mix(Arithmetic.Mix(_p[0], _p[1], 2.0 / 3.0), Arithmetic.Mix(_p[1], _p[2], 2.0 / 3.0),
                                                 2.0 / 3.0),
                                  Arithmetic.Mix(Arithmetic.Mix(_p[1], _p[2], 2.0 / 3.0), Arithmetic.Mix(_p[2], _p[3], 2.0 / 3.0),
                                                 2.0 / 3.0), 1.0 / 3.0),
                              Point(2.0 / 3.0));
     part3 = new CubicSegment(Color, Point(2.0 / 3.0),
                              Arithmetic.Mix(Arithmetic.Mix(_p[1], _p[2], 2.0 / 3.0), Arithmetic.Mix(_p[2], _p[3], 2.0 / 3.0),
                                             2.0 / 3.0),
                              _p[2] == _p[3] ? _p[3] : Arithmetic.Mix(_p[2], _p[3], 2.0 / 3.0), _p[3]);
 }
Example #12
0
        public static void GenerateSdf_legacy(FloatBmp output,
                                              Shape shape,
                                              double range,
                                              Vector2 scale,
                                              Vector2 translate)
        {
            int w = output.Width;
            int h = output.Height;

            for (int y = 0; y < h; ++y)
            {
                int row = shape.InverseYAxis ? h - y - 1 : y;
                for (int x = 0; x < w; ++x)
                {
                    double         dummy       = 0;
                    Vector2        p           = (new Vector2(x + 0.5f, y + 0.5) * scale) - translate;
                    SignedDistance minDistance = SignedDistance.INFINITE;
                    //TODO: review here
                    List <Contour> contours = shape.contours;
                    int            m        = contours.Count;
                    for (int n = 0; n < m; ++n)
                    {
                        Contour            contour = contours[n];
                        List <EdgeSegment> edges   = contour.edges;
                        int nn = edges.Count;
                        for (int i = 0; i < nn; ++i)
                        {
                            EdgeSegment    edge     = edges[i];
                            SignedDistance distance = edge.signedDistance(p, out dummy);
                            if (distance < minDistance)
                            {
                                minDistance = distance;
                            }
                        }
                    }
                    output.SetPixel(x, row, (float)(minDistance.distance / (range + 0.5f)));
                }
            }
        }
Example #13
0
        internal void SetOverlappedList(List <CornerList> overlappedList)
        {
            int m = overlappedList.Count;

            _overlappedEdgeList = new List <EdgeSegment[]>(m);
            for (int i = 0; i < m; ++i)
            {
#if DEBUG
                if (i == 124 || i == 389)
                {
                }
#endif
                CornerList    cornerList = overlappedList[i];
                int           count      = cornerList.Count;
                EdgeSegment[] corners    = new EdgeSegment[count];//overlapping corner region
                for (int a = 0; a < count; ++a)
                {
                    //ushort x = cornerList[a];
                    corners[a] = _corners[cornerList[a]].CenterSegment;
                }
                _overlappedEdgeList.Add(corners);
            }
        }
Example #14
0
        static Vertex2d ConvToV2d(PointD p) => new Vertex2d(p.X, p.Y); //temp

        /// <summary>
        /// fill inner and outer border from corner0 to corner1
        /// </summary>
        /// <param name="painter"></param>
        /// <param name="c0"></param>
        /// <param name="c1"></param>
        void FillBorders(AggPainter painter, ContourCorner c0, ContourCorner c1)
        {
            //counter-clockwise

            if (!c0.MiddlePoint_IsTouchPoint)
            {
                return;
            }

            //with a given corner, have have information of 3 points
            //left-point of the corner,=> from vertex
            //middle-point, current vertex
            //right-point,=> next vertex
            //a vertex may be touch-curve vertext, or 'not-touch-curve' vertex

            //'is not touch-curve point', => this vertex is a  control point of C3 or C4 curve,
            //-------------------------------------------------------

            if (c0.RightPoint_IsTouchPoint)
            {
                //c0 => touch curve
                //c1 => touch curve,
                //we create an imaginary line from  c0 to c1
                //then we create an 'inner border' of a line from c0 to c1
                //and we create an 'outer border' of a line from c0 to c1
                //
                using (Tools.BorrowVxs(out var v1))
                {
                    //1. inner-border, set fill mode to inform proper color encoding of inner border
                    _msdfEdgePxBlender.FillMode = MsdfEdgePixelBlender.BlenderFillMode.InnerBorder;



                    //2020-03-13, version 3 fill is still better than v3.1,
                    //TODO: review version v3.1


                    if (_use_v3_1)
                    {
                        //version 3.1 fill technique
                        CreateBorder(v1, ConvToV2d(c1.RightPoint), ConvToV2d(c1.MiddlePoint), ConvToV2d(c0.MiddlePoint), ConvToV2d(c0.LeftPoint));
                    }
                    else
                    {
                        //version 3 fill technique
                        CreateInnerBorder(v1,
                                          c0.MiddlePoint.X, c0.MiddlePoint.Y,
                                          c1.MiddlePoint.X, c1.MiddlePoint.Y, INNER_BORDER_W);
                    }

                    painter.Fill(v1, c0.InnerColor);
                    //-------------
                    v1.Clear(); //reuse
                                //2. outer-border, set fill mode too.


                    _msdfEdgePxBlender.FillMode = MsdfEdgePixelBlender.BlenderFillMode.OuterBorder;

                    if (_use_v3_1)
                    {
                        //version 3.1 fill technique
                        CreateBorder(v1, ConvToV2d(c0.LeftPoint), ConvToV2d(c0.MiddlePoint), ConvToV2d(c1.MiddlePoint), ConvToV2d(c1.RightPoint));
                    }
                    else
                    {
                        //version 3 fill technique
                        CreateOuterBorder(v1,
                                          c0.MiddlePoint.X, c0.MiddlePoint.Y,
                                          c1.MiddlePoint.X, c1.MiddlePoint.Y, OUTER_BORDER_W);
                    }


                    painter.Fill(v1, c0.OuterColor);
                }
            }
            else
            {
                //painter.CurrentBxtBlendOp = null;

                //**
                //c0 is touch line,
                //but c1 is not, this means=> next segment will be a curve(C3 or C4 curve)
                //
                EdgeSegment ownerSeg = c1.CenterSegment;

                switch (ownerSeg.SegmentKind)
                {
                default: throw new NotSupportedException();

                case EdgeSegmentKind.CubicSegment:
                {
                    //approximate
                    CubicSegment cs = (CubicSegment)ownerSeg;
                    using (Tools.BorrowVxs(out var v1))
                        using (Tools.BorrowShapeBuilder(out var b))
                            using (Tools.BorrowStroke(out var strk))
                            {
                                b.MoveTo(cs.P0.x + _dx, cs.P0.y + _dy) //...
                                .Curve4To(cs.P1.x + _dx, cs.P1.y + _dy,
                                          cs.P2.x + _dx, cs.P2.y + _dy,
                                          cs.P3.x + _dx, cs.P3.y + _dy)
                                .NoMore()
                                .Flatten();


                                //-----------------------
                                //fill outside part of the curve
                                strk.Width = CURVE_STROKE_EACHSIDE * 2;
                                strk.StrokeSideForOpenShape = StrokeSideForOpenShape.Outside;
                                strk.MakeVxs(b.CurrentSharedVxs, v1);

                                painter.Fill(v1, c0.OuterColor);
                                //-----------------------
                                //fill inside part of the curve
                                v1.Clear(); //reuse
                                strk.StrokeSideForOpenShape = StrokeSideForOpenShape.Inside;
                                strk.MakeVxs(b.CurrentSharedVxs, v1);
                                painter.Fill(v1, c0.InnerColor);
                                //-----------------------
                            }
                }
                break;

                case EdgeSegmentKind.QuadraticSegment:
                {
                    QuadraticSegment qs = (QuadraticSegment)ownerSeg;

                    using (Tools.BorrowVxs(out var v1))
                        using (Tools.BorrowShapeBuilder(out var b))
                            using (Tools.BorrowStroke(out var strk))
                            {
                                b.MoveTo(qs.P0.x + _dx, qs.P0.y + _dy)//...
                                .Curve3To(qs.P1.x + _dx, qs.P1.y + _dy,
                                          qs.P2.x + _dx, qs.P2.y + _dy)
                                .NoMore()
                                .Flatten();

                                //-----------------------
                                //fill outside part of the curve
                                strk.Width = CURVE_STROKE_EACHSIDE * 2;
                                strk.StrokeSideForOpenShape = StrokeSideForOpenShape.Outside;
                                strk.MakeVxs(b.CurrentSharedVxs, v1);
                                painter.Fill(v1, c0.OuterColor);
                                //-----------------------
                                //fill inside part of the curve
                                v1.Clear();//reuse
                                strk.StrokeSideForOpenShape = StrokeSideForOpenShape.Inside;
                                strk.MakeVxs(b.CurrentSharedVxs, v1);
                                painter.Fill(v1, c0.InnerColor);
                                //-----------------------
                            }
                }
                break;
                }
            }
        }
 public abstract void splitInThirds(
     out EdgeSegment part1,
     out EdgeSegment part2,
     out EdgeSegment part3);
Example #16
0
        //siged distance field generator

        public static void GenerateSdf(FloatBmp output,
                                       Shape shape,
                                       double range,
                                       Vector2 scale,
                                       Vector2 translate)
        {
            List <Contour> contours = shape.contours;
            int            contourCount = contours.Count;
            int            w = output.Width, h = output.Height;
            List <int>     windings = new List <int>(contourCount);

            for (int i = 0; i < contourCount; ++i)
            {
                windings.Add(contours[i].winding());
            }

            //# ifdef MSDFGEN_USE_OPENMP
            //#pragma omp parallel
            //#endif
            {
                //# ifdef MSDFGEN_USE_OPENMP
                //#pragma omp for
                //#endif
                double[] contourSD = new double[contourCount];
                for (int y = 0; y < h; ++y)
                {
                    int row = shape.InverseYAxis ? h - y - 1 : y;
                    for (int x = 0; x < w; ++x)
                    {
                        double  dummy   = 0;
                        Vector2 p       = (new Vector2(x + .5, y + .5) / scale) - translate;
                        double  negDist = -SignedDistance.INFINITE.distance;
                        double  posDist = SignedDistance.INFINITE.distance;
                        int     winding = 0;


                        for (int i = 0; i < contourCount; ++i)
                        {
                            Contour            contour     = contours[i];
                            SignedDistance     minDistance = SignedDistance.INFINITE;
                            List <EdgeSegment> edges       = contour.edges;
                            int edgeCount = edges.Count;
                            for (int ee = 0; ee < edgeCount; ++ee)
                            {
                                EdgeSegment    edge     = edges[ee];
                                SignedDistance distance = edge.signedDistance(p, out dummy);
                                if (distance < minDistance)
                                {
                                    minDistance = distance;
                                }
                            }

                            contourSD[i] = minDistance.distance;
                            if (windings[i] > 0 && minDistance.distance >= 0 && Math.Abs(minDistance.distance) < Math.Abs(posDist))
                            {
                                posDist = minDistance.distance;
                            }
                            if (windings[i] < 0 && minDistance.distance <= 0 && Math.Abs(minDistance.distance) < Math.Abs(negDist))
                            {
                                negDist = minDistance.distance;
                            }
                        }

                        double sd = SignedDistance.INFINITE.distance;
                        if (posDist >= 0 && Math.Abs(posDist) <= Math.Abs(negDist))
                        {
                            sd      = posDist;
                            winding = 1;
                            for (int i = 0; i < contourCount; ++i)
                            {
                                if (windings[i] > 0 && contourSD[i] > sd && Math.Abs(contourSD[i]) < Math.Abs(negDist))
                                {
                                    sd = contourSD[i];
                                }
                            }
                        }
                        else if (negDist <= 0 && Math.Abs(negDist) <= Math.Abs(posDist))
                        {
                            sd      = negDist;
                            winding = -1;
                            for (int i = 0; i < contourCount; ++i)
                            {
                                if (windings[i] < 0 && contourSD[i] < sd && Math.Abs(contourSD[i]) < Math.Abs(posDist))
                                {
                                    sd = contourSD[i];
                                }
                            }
                        }
                        for (int i = 0; i < contourCount; ++i)
                        {
                            if (windings[i] != winding && Math.Abs(contourSD[i]) < Math.Abs(sd))
                            {
                                sd = contourSD[i];
                            }
                        }

                        output.SetPixel(x, row, (float)(sd / range + .5));
                    }
                }
            }
        }
 public override void splitInThirds(out EdgeSegment part1, out EdgeSegment part2, out EdgeSegment part3)
 {
     part1 = new QuadraticSegment(p[0], mix(p[0], p[1], 1 / 3.0), point(1 / 3.0), this.color);
     part2 = new QuadraticSegment(point(1 / 3.0), mix(mix(p[0], p[1], 5 / 9.0), mix(p[1], p[2], 4 / 9.0), .5), point(2 / 3.0), this.color);
     part3 = new QuadraticSegment(point(2 / 3.0), mix(p[1], p[2], 2 / 3.0), p[2], this.color);
 }
Example #18
0
        public static void generateMSDF(FloatRGBBmp output, Shape shape, double range, Vector2 scale, Vector2 translate, double edgeThreshold)
        {
            List <Contour> contours     = shape.contours;
            int            contourCount = contours.Count;
            int            w            = output.Width;
            int            h            = output.Height;
            List <int>     windings     = new List <int>(contourCount);

            for (int i = 0; i < contourCount; ++i)
            {
                windings.Add(contours[i].winding());
            }

            var contourSD = new MultiDistance[contourCount];

            for (int y = 0; y < h; ++y)
            {
                int row = shape.InverseYAxis ? h - y - 1 : y;
                for (int x = 0; x < w; ++x)
                {
                    Vector2   p  = (new Vector2(x + .5, y + .5) / scale) - translate;
                    EdgePoint sr = new EdgePoint {
                        minDistance = SignedDistance.INFINITE
                    },
                              sg = new EdgePoint {
                        minDistance = SignedDistance.INFINITE
                    },
                              sb = new EdgePoint {
                        minDistance = SignedDistance.INFINITE
                    };
                    double d       = Math.Abs(SignedDistance.INFINITE.distance);
                    double negDist = -Math.Abs(SignedDistance.INFINITE.distance);
                    double posDist = Math.Abs(SignedDistance.INFINITE.distance);
                    int    winding = 0;

                    for (int n = 0; n < contourCount; ++n)
                    {
                        //for-each contour
                        Contour            contour = contours[n];
                        List <EdgeSegment> edges   = contour.edges;
                        int       edgeCount        = edges.Count;
                        EdgePoint r = new EdgePoint {
                            minDistance = SignedDistance.INFINITE
                        },
                                  g = new EdgePoint {
                            minDistance = SignedDistance.INFINITE
                        },
                                  b = new EdgePoint {
                            minDistance = SignedDistance.INFINITE
                        };
                        for (int ee = 0; ee < edgeCount; ++ee)
                        {
                            EdgeSegment    edge     = edges[ee];
                            SignedDistance distance = edge.signedDistance(p, out double param);
                            if (edge.HasComponent(EdgeColor.RED) && distance < r.minDistance)
                            {
                                r.minDistance = distance;
                                r.nearEdge    = edge;
                                r.nearParam   = param;
                            }
                            if (edge.HasComponent(EdgeColor.GREEN) && distance < g.minDistance)
                            {
                                g.minDistance = distance;
                                g.nearEdge    = edge;
                                g.nearParam   = param;
                            }
                            if (edge.HasComponent(EdgeColor.BLUE) && distance < b.minDistance)
                            {
                                b.minDistance = distance;
                                b.nearEdge    = edge;
                                b.nearParam   = param;
                            }
                        }
                        //----------------
                        if (r.minDistance < sr.minDistance)
                        {
                            sr = r;
                        }
                        if (g.minDistance < sg.minDistance)
                        {
                            sg = g;
                        }
                        if (b.minDistance < sb.minDistance)
                        {
                            sb = b;
                        }
                        //----------------
                        double medMinDistance = Math.Abs(median(r.minDistance.distance, g.minDistance.distance, b.minDistance.distance));
                        if (medMinDistance < d)
                        {
                            d       = medMinDistance;
                            winding = -windings[n];
                        }

                        if (r.nearEdge != null)
                        {
                            r.nearEdge.distanceToPseudoDistance(ref r.minDistance, p, r.nearParam);
                        }
                        if (g.nearEdge != null)
                        {
                            g.nearEdge.distanceToPseudoDistance(ref g.minDistance, p, g.nearParam);
                        }
                        if (b.nearEdge != null)
                        {
                            b.nearEdge.distanceToPseudoDistance(ref b.minDistance, p, b.nearParam);
                        }
                        //--------------
                        medMinDistance   = median(r.minDistance.distance, g.minDistance.distance, b.minDistance.distance);
                        contourSD[n].r   = r.minDistance.distance;
                        contourSD[n].g   = g.minDistance.distance;
                        contourSD[n].b   = b.minDistance.distance;
                        contourSD[n].med = medMinDistance;
                        if (windings[n] > 0 && medMinDistance >= 0 && Math.Abs(medMinDistance) < Math.Abs(posDist))
                        {
                            posDist = medMinDistance;
                        }
                        if (windings[n] < 0 && medMinDistance <= 0 && Math.Abs(medMinDistance) < Math.Abs(negDist))
                        {
                            negDist = medMinDistance;
                        }
                    }
                    if (sr.nearEdge != null)
                    {
                        sr.nearEdge.distanceToPseudoDistance(ref sr.minDistance, p, sr.nearParam);
                    }
                    if (sg.nearEdge != null)
                    {
                        sg.nearEdge.distanceToPseudoDistance(ref sg.minDistance, p, sg.nearParam);
                    }
                    if (sb.nearEdge != null)
                    {
                        sb.nearEdge.distanceToPseudoDistance(ref sb.minDistance, p, sb.nearParam);
                    }

                    MultiDistance msd;
                    msd.r = msd.g = msd.b = msd.med = SignedDistance.INFINITE.distance;
                    if (posDist >= 0 && Math.Abs(posDist) <= Math.Abs(negDist))
                    {
                        msd.med = SignedDistance.INFINITE.distance;
                        winding = 1;
                        for (int i = 0; i < contourCount; ++i)
                        {
                            if (windings[i] > 0 && contourSD[i].med > msd.med && Math.Abs(contourSD[i].med) < Math.Abs(negDist))
                            {
                                msd = contourSD[i];
                            }
                        }
                    }
                    else if (negDist <= 0 && Math.Abs(negDist) <= Math.Abs(posDist))
                    {
                        msd.med = -SignedDistance.INFINITE.distance;
                        winding = -1;
                        for (int i = 0; i < contourCount; ++i)
                        {
                            if (windings[i] < 0 && contourSD[i].med < msd.med && Math.Abs(contourSD[i].med) < Math.Abs(posDist))
                            {
                                msd = contourSD[i];
                            }
                        }
                    }
                    for (int i = 0; i < contourCount; ++i)
                    {
                        if (windings[i] != winding && Math.Abs(contourSD[i].med) < Math.Abs(msd.med))
                        {
                            msd = contourSD[i];
                        }
                    }
                    if (median(sr.minDistance.distance, sg.minDistance.distance, sb.minDistance.distance) == msd.med)
                    {
                        msd.r = sr.minDistance.distance;
                        msd.g = sg.minDistance.distance;
                        msd.b = sb.minDistance.distance;
                    }

                    output.SetPixel(x, row,
                                    new FloatRGB(
                                        (float)(msd.r / range + .5),
                                        (float)(msd.g / range + .5),
                                        (float)(msd.b / range + .5)
                                        ));
                }
            }

            if (edgeThreshold > 0)
            {
                msdfErrorCorrection(output, edgeThreshold / (scale * range));
            }
        }
Example #19
0
        public static void generateMSDF_legacy(FloatRGBBmp output, Shape shape, double range, Vector2 scale, Vector2 translate,
                                               double edgeThreshold)
        {
            int w = output.Width;
            int h = output.Height;

            //#ifdef MSDFGEN_USE_OPENMP
            //    #pragma omp parallel for
            //#endif
            for (int y = 0; y < h; ++y)
            {
                int row = shape.InverseYAxis ? h - y - 1 : y;
                for (int x = 0; x < w; ++x)
                {
                    Vector2   p = (new Vector2(x + .5, y + .5) / scale) - translate;
                    EdgePoint r = new EdgePoint {
                        minDistance = SignedDistance.INFINITE
                    },
                              g = new EdgePoint {
                        minDistance = SignedDistance.INFINITE
                    },
                              b = new EdgePoint {
                        minDistance = SignedDistance.INFINITE
                    };
                    //r.nearEdge = g.nearEdge = b.nearEdge = null;
                    //r.nearParam = g.nearParam = b.nearParam = 0;
                    List <Contour> contours = shape.contours;
                    int            m        = contours.Count;
                    for (int n = 0; n < m; ++n)
                    {
                        Contour            contour = contours[n];
                        List <EdgeSegment> edges   = contour.edges;
                        int j = edges.Count;
                        for (int i = 0; i < j; ++i)
                        {
                            EdgeSegment    edge     = edges[i];
                            SignedDistance distance = edge.signedDistance(p, out double param);

                            if (edge.HasComponent(EdgeColor.RED) && distance < r.minDistance)
                            {
                                r.minDistance = distance;
                                r.nearEdge    = edge;
                                r.nearParam   = param;
                            }
                            if (edge.HasComponent(EdgeColor.GREEN) && distance < g.minDistance)
                            {
                                g.minDistance = distance;
                                g.nearEdge    = edge;
                                g.nearParam   = param;
                            }
                            if (edge.HasComponent(EdgeColor.BLUE) && distance < b.minDistance)
                            {
                                b.minDistance = distance;
                                b.nearEdge    = edge;
                                b.nearParam   = param;
                            }
                        }
                        if (r.nearEdge != null)
                        {
                            r.nearEdge.distanceToPseudoDistance(ref r.minDistance, p, r.nearParam);
                        }
                        if (g.nearEdge != null)
                        {
                            g.nearEdge.distanceToPseudoDistance(ref g.minDistance, p, g.nearParam);
                        }
                        if (b.nearEdge != null)
                        {
                            b.nearEdge.distanceToPseudoDistance(ref b.minDistance, p, b.nearParam);
                        }

                        output.SetPixel(x, row,
                                        new FloatRGB(
                                            (float)(r.minDistance.distance / range + .5),
                                            (float)(g.minDistance.distance / range + .5),
                                            (float)(b.minDistance.distance / range + .5)
                                            ));
                    }
                }
            }

            if (edgeThreshold > 0)
            {
                msdfErrorCorrection(output, edgeThreshold / (scale * range));
            }
        }
Example #20
0
        static void GenerateMSDF3(FloatRGBBmp output, Shape shape, double range, Vector2 scale, Vector2 translate, double edgeThreshold, EdgeBmpLut lut)
        {
            //----------------------
            //this is our extension,
            //we use lookup bitmap (lut) to check
            //what is the nearest contour of a given pixel.
            //----------------------

            int w = output.Width;
            int h = output.Height;

            EdgeSegment[] singleSegment = new EdgeSegment[1];//temp array for



            for (int y = 0; y < h; ++y)
            {
                for (int x = 0; x < w; ++x)
                {
                    //PER-PIXEL-OPERATION
                    //check preview pixel

                    int lutPix  = lut.GetPixel(x, y);
                    int lutPixR = (lutPix & 0xFF);
                    int lutPixG = (lutPix >> 8) & 0xff;
                    int lutPixB = (lutPix >> 16) & 0xff;

                    if (lutPixG == 0)
                    {
                        continue;               //black=> completely outside, skip
                    }
                    if (lutPixG == EdgeBmpLut.AREA_INSIDE_COVERAGE100 ||
                        lutPixG == EdgeBmpLut.AREA_INSIDE_COVERAGE50 ||
                        lutPixG == EdgeBmpLut.AREA_INSIDE_COVERAGEX)
                    {
                        //inside the contour => fill all with white
                        output.SetPixel(x, y, new FloatRGB(1f, 1f, 1f));
                        continue;
                    }

                    //reset variables
                    EdgePoint r = new EdgePoint {
                        minDistance = SignedDistance.INFINITE
                    },
                              g = new EdgePoint {
                        minDistance = SignedDistance.INFINITE
                    },
                              b = new EdgePoint {
                        minDistance = SignedDistance.INFINITE
                    };

                    bool useR, useG, useB;
                    useR = useG = useB = true;
                    //------

                    Vector2 p = (new Vector2(x + .5, y + .5) / scale) - translate;

                    EdgeStructure edgeStructure = lut.GetEdgeStructure(x, y);

#if DEBUG
                    if (edgeStructure.IsEmpty)
                    {
                        //should not occurs
                        throw new NotSupportedException();
                    }
#endif
                    EdgeSegment[] edges = null;
                    if (edgeStructure.HasOverlappedSegments)
                    {
                        edges = edgeStructure.Segments;
                    }
                    else
                    {
                        singleSegment[0] = edgeStructure.Segment;
                        edges            = singleSegment;
                    }
                    //-------------

                    for (int i = 0; i < edges.Length; ++i)
                    {
                        EdgeSegment edge = edges[i];

                        SignedDistance distance = edge.signedDistance(p, out double param);//***

                        if (edge.HasComponent(EdgeColor.RED) && distance < r.minDistance)
                        {
                            r.minDistance = distance;
                            r.nearEdge    = edge;
                            r.nearParam   = param;
                            useR          = false;
                        }
                        if (edge.HasComponent(EdgeColor.GREEN) && distance < g.minDistance)
                        {
                            g.minDistance = distance;
                            g.nearEdge    = edge;
                            g.nearParam   = param;
                            useG          = false;
                        }
                        if (edge.HasComponent(EdgeColor.BLUE) && distance < b.minDistance)
                        {
                            b.minDistance = distance;
                            b.nearEdge    = edge;
                            b.nearParam   = param;
                            useB          = false;
                        }
                    }

                    double contour_r = r.CalculateContourColor(p);
                    double contour_g = g.CalculateContourColor(p);
                    double contour_b = b.CalculateContourColor(p);

                    if (useB && contour_b <= SignedDistance.INFINITE.distance)
                    {
                        contour_b = 1 * range;
                    }
                    if (useG && contour_g <= SignedDistance.INFINITE.distance)
                    {
                        contour_g = 1 * range;
                    }
                    if (useR && contour_r <= SignedDistance.INFINITE.distance)
                    {
                        contour_r = 1 * range;
                    }

                    output.SetPixel(x, y,
                                    new FloatRGB(
                                        (float)(contour_r / range + .5),
                                        (float)(contour_g / range + .5),
                                        (float)(contour_b / range + .5)
                                        ));
                }
            }
        }
Example #21
0
        public static void edgeColoringSimple(Shape shape, double angleThreshold, ulong seed = 0)
        {
            double     crossThreshold = Math.Sin(angleThreshold);
            List <int> corners        = new List <int>(); //TODO: review reusable list

            // for (std::vector<Contour>::iterator contour = shape.contours.begin(); contour != shape.contours.end(); ++contour)
            foreach (Contour contour in shape.contours)
            {
                // Identify corners
                corners.Clear();
                List <EdgeHolder> edges = contour.edges;
                int edgeCount           = edges.Count;
                if (edgeCount != 0)
                {
                    Vector2 prevDirection = edges[edgeCount - 1].direction(1);// (*(contour->edges.end() - 1))->direction(1);
                    for (int i = 0; i < edgeCount; ++i)
                    {
                        EdgeHolder edge = edges[i];
                        if (isCorner(prevDirection.normalize(),
                                     edge.direction(0).normalize(), crossThreshold))
                        {
                            corners.Add(i);
                        }
                        prevDirection = edge.direction(1);
                    }
                }

                // Smooth contour
                if (corners.Count == 0) //is empty
                {
                    for (int i = edgeCount - 1; i >= 0; --i)
                    {
                        edges[i].color = EdgeColor.WHITE;
                    }
                }
                else if (corners.Count == 1)
                {
                    // "Teardrop" case
                    EdgeColor[] colors = { EdgeColor.WHITE, EdgeColor.WHITE, EdgeColor.BLACK };
                    switchColor(ref colors[0], ref seed);
                    colors[2] = colors[0];
                    switchColor(ref colors[2], ref seed);

                    int corner = corners[0];
                    if (edgeCount >= 3)
                    {
                        int m = edgeCount;
                        for (int i = 0; i < m; ++i)
                        {
                            //TODO: review here
                            contour.edges[(corner + i) % m].color = colors[((int)(3 + 2.875 * i / (m - 1) - 1.4375 + .5) - 3) + 1];
                            //(colors + 1)[int(3 + 2.875 * i / (m - 1) - 1.4375 + .5) - 3];
                        }
                    }
                    else if (edgeCount >= 1)
                    {
                        // Less than three edge segments for three colors => edges must be split
                        EdgeSegment[] parts = new EdgeSegment[7]; //empty array, TODO: review array alloc here
                        edges[0].edgeSegment.splitInThirds(
                            out parts[0 + 3 * corner],
                            out parts[1 + 3 * corner],
                            out parts[2 + 3 * corner]);

                        if (edgeCount >= 2)
                        {
                            edges[1].edgeSegment.splitInThirds(
                                out parts[3 - 3 * corner],
                                out parts[4 - 3 * corner],
                                out parts[5 - 3 * corner]
                                );
                            parts[0].color = parts[1].color = colors[0];
                            parts[2].color = parts[3].color = colors[1];
                            parts[4].color = parts[5].color = colors[2];
                        }
                        else
                        {
                            parts[0].color = colors[0];
                            parts[1].color = colors[1];
                            parts[2].color = colors[2];
                        }
                        contour.edges.Clear();
                        for (int i = 0; i < 7; ++i)
                        {
                            edges.Add(new EdgeHolder(parts[i]));
                        }
                    }
                }
                // Multiple corners
                else
                {
                    int       cornerCount = corners.Count;
                    int       spline      = 0;
                    int       start       = corners[0];
                    int       m           = contour.edges.Count;
                    EdgeColor color       = EdgeColor.WHITE;
                    switchColor(ref color, ref seed);
                    EdgeColor initialColor = color;
                    for (int i = 0; i < m; ++i)
                    {
                        int index = (start + i) % m;
                        if (spline + 1 < cornerCount && corners[spline + 1] == index)
                        {
                            ++spline;
                            switchColor(ref color, ref seed, (EdgeColor)(((spline == cornerCount - 1) ? 1 : 0) * (int)initialColor));
                        }
                        edges[index].color = color;
                    }
                }
            }
        }
        public void AddEdge(EdgeSegment edge)
        {
            EdgeHolder holder = new EdgeHolder(edge);

            edges.Add(holder);
        }
Example #23
0
 public override void splitInThirds(out EdgeSegment part1, out EdgeSegment part2, out EdgeSegment part3)
 {
     part1 = new QuadraticSegment(_p0, mix(_p0, _p1, 1 / 3.0), point(1 / 3.0), this.color);
     part2 = new QuadraticSegment(point(1 / 3.0), mix(mix(_p0, _p1, 5 / 9.0), mix(_p1, _p2, 4 / 9.0), .5), point(2 / 3.0), this.color);
     part3 = new QuadraticSegment(point(2 / 3.0), mix(_p1, _p2, 2 / 3.0), _p2, this.color);
 }
 public override void splitInThirds(out EdgeSegment part1, out EdgeSegment part2, out EdgeSegment part3)
 {
     part1 = new LinearSegment(p[0], point(1 / 3.0), this.color);
     part2 = new LinearSegment(point(1 / 3.0), point(2 / 3.0), this.color);
     part3 = new LinearSegment(point(2 / 3.0), p[1], this.color);
 }
        public static void edgeColoringSimple(Shape shape, double angleThreshold)
        {
            double     crossThreshold = Math.Sin(angleThreshold);
            List <int> corners        = new List <int>();

            // for (std::vector<Contour>::iterator contour = shape.contours.begin(); contour != shape.contours.end(); ++contour)
            foreach (Contour contour in shape.contours)
            {
                // Identify corners
                corners.Clear();
                List <EdgeHolder> edges = contour.edges;
                int edgeCount           = edges.Count;
                if (edgeCount != 0)
                {
                    Vector2 prevDirection = edges[edgeCount - 1].Direction(1);// (*(contour->edges.end() - 1))->direction(1);
                    for (int i = 0; i < edgeCount; ++i)
                    {
                        EdgeHolder edge = edges[i];
                        if (isCorner(prevDirection.normalize(),
                                     edge.Direction(0).normalize(), crossThreshold))
                        {
                            corners.Add(i);
                        }
                        prevDirection = edge.Direction(1);
                    }
                }

                // Smooth contour
                if (corners.Count == 0) //is empty
                {
                    for (int i = edgeCount - 1; i >= 0; --i)
                    {
                        edges[i].color = EdgeColor.WHITE;
                    }
                }
                else if (corners.Count == 1)
                {
                    // "Teardrop" case
                    EdgeColor[] colors = { EdgeColor.MAGENTA, EdgeColor.WHITE, EdgeColor.YELLOW };
                    int         corner = corners[0];
                    if (edgeCount >= 3)
                    {
                        int m = edgeCount;
                        for (int i = 0; i < m; ++i)
                        {
                            //TODO: review here
                            contour.edges[(corner + i) % m].color = colors[((int)(3 + 2.875 * i / (m - 1) - 1.4375 + .5) - 3) + 1];
                            //(colors + 1)[int(3 + 2.875 * i / (m - 1) - 1.4375 + .5) - 3];
                        }
                    }
                    else if (edgeCount >= 1)
                    {
                        // Less than three edge segments for three colors => edges must be split
                        EdgeSegment[] parts = new EdgeSegment[7]; //empty array
                        edges[0].edgeSegment.splitInThirds(
                            out parts[0 + 3 * corner],
                            out parts[1 + 3 * corner],
                            out parts[2 + 3 * corner]);

                        if (edgeCount >= 2)
                        {
                            edges[1].edgeSegment.splitInThirds(
                                out parts[3 - 3 * corner],
                                out parts[4 - 3 * corner],
                                out parts[5 - 3 * corner]
                                );
                            parts[0].color = parts[1].color = colors[0];
                            parts[2].color = parts[3].color = colors[1];
                            parts[4].color = parts[5].color = colors[2];
                        }
                        else
                        {
                            parts[0].color = colors[0];
                            parts[1].color = colors[1];
                            parts[2].color = colors[2];
                        }
                        contour.edges.Clear();
                        for (int i = 0; i < 7; ++i)
                        {
                            edges.Add(new EdgeHolder(parts[i]));
                        }
                    }
                }
                // Multiple corners
                else
                {
                    int cornerCount = corners.Count;
                    // CMYCMYCMYCMY / YMYCMYC if corner count % 3 == 1
                    EdgeColor[] colors = { cornerCount % 3 == 1 ? EdgeColor.YELLOW : EdgeColor.CYAN, EdgeColor.CYAN, EdgeColor.MAGENTA, EdgeColor.YELLOW };
                    int         spline = 0;
                    int         start  = corners[0];
                    int         m      = contour.edges.Count;
                    for (int i = 0; i < m; ++i)
                    {
                        int index = (start + i) % m;
                        if (cornerCount > spline + 1 && corners[spline + 1] == index)
                        {
                            ++spline;
                        }

                        int tmp = (spline % 3 - ((spline == 0) ? 1 : 0));
                        edges[index].color = colors[tmp + 1];
                        //contour->edges[index]->color = (colors + 1)[spline % 3 - !spline];
                    }
                }
            }
        }
Example #26
0
 public override void SplitInThirds(out EdgeSegment part1, out EdgeSegment part2, out EdgeSegment part3)
 {
     part1 = new LinearSegment(_p[0], Point(1.0 / 3.0), Color);
     part2 = new LinearSegment(Point(1.0 / 3.0), Point(2.0 / 3.0), Color);
     part3 = new LinearSegment(Point(2.0 / 3.0), _p[1], Color);
 }