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