package d2raster

import (
	
	
	
	

	
	
)

const (
	maxCurveErrorPixels = 0.25
	maxCurveDepth       = 24
	geometryEpsilon     = 1e-12
)

type subpath struct {
	points []d2scene.Point
	closed bool
}

type strokeRun struct {
	points []d2scene.Point
	closed bool
}

func flattenTolerance( d2scene.Matrix) float64 {
	 := math.Max(
		math.Max(math.Abs(.A), math.Abs(.B)),
		math.Max(math.Abs(.C), math.Abs(.D)),
	)
	if !finite() {
		return math.SmallestNonzeroFloat64
	}
	if  == 0 {
		return math.MaxFloat64
	}
	// Normalize before calculating the exact largest singular value. Divide in
	// two stages so both enormous and subnormal finite scales retain a
	// meaningful reciprocal tolerance without changing ordinary-scale output.
	 := (d2scene.Matrix{
		A: .A / ,
		B: .B / ,
		C: .C / ,
		D: .D / ,
	}).MaxScale()
	 := maxCurveErrorPixels / 
	if  < /math.MaxFloat64 {
		return math.MaxFloat64
	}
	 :=  / 
	if  == 0 {
		return math.SmallestNonzeroFloat64
	}
	return 
}

func flattenScenePath( context.Context,  d2scene.Path,  d2scene.Matrix,  func() error) ([]subpath, error) {
	 := flattenTolerance()
	var  []subpath
	var  subpath
	var ,  d2scene.Point
	 := false

	 := func( bool) {
		if len(.points) != 0 {
			.closed = 
			 = append(, )
		}
		 = subpath{}
	}
	 := func( d2scene.Point) error {
		if !finitePoint() {
			return fmt.Errorf("non-finite point")
		}
		if  := ();  != nil {
			return 
		}
		.points = append(.points, )
		, ,  = , , true
		return nil
	}
	 := func( d2scene.Point) error {
		if !finitePoint() {
			return fmt.Errorf("non-finite point")
		}
		if  := ();  != nil {
			return 
		}
		if len(.points) == 0 || !samePoint(.points[len(.points)-1], ) {
			.points = append(.points, )
		}
		return nil
	}
	 := func() {
		if len(.points) == 0 {
			.points = append(.points, )
		}
	}

	for ,  := range .Commands {
		if  := .Err();  != nil {
			return nil, 
		}
		switch .Kind {
		case d2scene.MoveCommand:
			(false)
			if  := (.P1);  != nil {
				return nil, fmt.Errorf("command %d: %w", , )
			}
		case d2scene.LineCommand:
			if ! {
				return nil, fmt.Errorf("command %d: line before move", )
			}
			()
			if  := (.P1);  != nil {
				return nil, fmt.Errorf("command %d: %w", , )
			}
			 = .P1
		case d2scene.QuadraticCommand:
			if ! {
				return nil, fmt.Errorf("command %d: quadratic before move", )
			}
			if !finitePoint(.P1) || !finitePoint(.P2) {
				return nil, fmt.Errorf("command %d: non-finite point", )
			}
			()
			if  := flattenQuadratic(, , .P1, .P2, , 0, );  != nil {
				return nil, fmt.Errorf("command %d: %w", , )
			}
			 = .P2
		case d2scene.CubicCommand:
			if ! {
				return nil, fmt.Errorf("command %d: cubic before move", )
			}
			if !finitePoint(.P1) || !finitePoint(.P2) || !finitePoint(.P3) {
				return nil, fmt.Errorf("command %d: non-finite point", )
			}
			()
			if  := flattenCubic(, , .P1, .P2, .P3, , 0, );  != nil {
				return nil, fmt.Errorf("command %d: %w", , )
			}
			 = .P3
		case d2scene.ArcCommand:
			if ! {
				return nil, fmt.Errorf("command %d: arc before move", )
			}
			if !finitePoint(.P1) || !finite(.RadiusX) || !finite(.RadiusY) || !finite(.Rotation) {
				return nil, fmt.Errorf("command %d: non-finite arc", )
			}
			()
			if  := flattenArc(, , , , maxCurveErrorPixels, );  != nil {
				return nil, fmt.Errorf("command %d: %w", , )
			}
			 = .P1
		case d2scene.CloseCommand:
			if ! {
				return nil, fmt.Errorf("command %d: close before move", )
			}
			if  := ();  != nil {
				return nil, fmt.Errorf("command %d: %w", , )
			}
			(true)
			 = 
			 = true
		default:
			return nil, fmt.Errorf("command %d: unknown kind %d", , .Kind)
		}
	}
	(false)
	return , nil
}

func roundedRectSubpaths( context.Context,  d2scene.Rect,  float64,  func() error) ([]subpath, error) {
	 := .Box
	if .Width == 0 || .Height == 0 {
		return nil, nil
	}
	 := math.Min(.RadiusX, .Width/2)
	 := math.Min(.RadiusY, .Height/2)
	if  == 0 ||  == 0 {
		 := []d2scene.Point{
			{X: .X, Y: .Y},
			{X: .X + .Width, Y: .Y},
			{X: .X + .Width, Y: .Y + .Height},
			{X: .X, Y: .Y + .Height},
		}
		for range  {
			if  := ();  != nil {
				return nil, 
			}
		}
		return []subpath{{points: , closed: true}}, nil
	}

	 := make([]d2scene.Point, 0, 8)
	 := func( d2scene.Point) error {
		if  := ();  != nil {
			return 
		}
		if len() == 0 || !samePoint([len()-1], ) {
			 = append(, )
		}
		return nil
	}
	if  := (d2scene.Point{X: .X + , Y: .Y});  != nil {
		return nil, 
	}
	if  := (d2scene.Point{X: .X + .Width - , Y: .Y});  != nil {
		return nil, 
	}
	 := 0.5522847498307936
	 := [][4]d2scene.Point{
		{{X: .X + .Width - , Y: .Y}, {X: .X + .Width -  + *, Y: .Y}, {X: .X + .Width, Y: .Y +  - *}, {X: .X + .Width, Y: .Y + }},
		{{X: .X + .Width, Y: .Y + .Height - }, {X: .X + .Width, Y: .Y + .Height -  + *}, {X: .X + .Width -  + *, Y: .Y + .Height}, {X: .X + .Width - , Y: .Y + .Height}},
		{{X: .X + , Y: .Y + .Height}, {X: .X +  - *, Y: .Y + .Height}, {X: .X, Y: .Y + .Height -  + *}, {X: .X, Y: .Y + .Height - }},
		{{X: .X, Y: .Y + }, {X: .X, Y: .Y +  - *}, {X: .X +  - *, Y: .Y}, {X: .X + , Y: .Y}},
	}
	 := []d2scene.Point{
		{X: .X + .Width, Y: .Y + .Height - },
		{X: .X + , Y: .Y + .Height},
		{X: .X, Y: .Y + },
	}
	for ,  := range  {
		if  := .Err();  != nil {
			return nil, 
		}
		if  != 0 {
			if  := ([-1]);  != nil {
				return nil, 
			}
		}
		if  := flattenCubic(, [0], [1], [2], [3], , 0, );  != nil {
			return nil, 
		}
	}
	return []subpath{{points: , closed: true}}, nil
}

func ellipseSubpaths( context.Context,  d2scene.Point, , ,  float64,  func() error) ([]subpath, error) {
	if  == 0 ||  == 0 {
		return nil, nil
	}
	 := 0.5522847498307936
	 := [][4]d2scene.Point{
		{{X: .X + , Y: .Y}, {X: .X + , Y: .Y + *}, {X: .X + *, Y: .Y + }, {X: .X, Y: .Y + }},
		{{X: .X, Y: .Y + }, {X: .X - *, Y: .Y + }, {X: .X - , Y: .Y + *}, {X: .X - , Y: .Y}},
		{{X: .X - , Y: .Y}, {X: .X - , Y: .Y - *}, {X: .X - *, Y: .Y - }, {X: .X, Y: .Y - }},
		{{X: .X, Y: .Y - }, {X: .X + *, Y: .Y - }, {X: .X + , Y: .Y - *}, {X: .X + , Y: .Y}},
	}
	 := make([]d2scene.Point, 0, 32)
	 := func( d2scene.Point) error {
		if  := ();  != nil {
			return 
		}
		if len() == 0 || !samePoint([len()-1], ) {
			 = append(, )
		}
		return nil
	}
	if  := ([0][0]);  != nil {
		return nil, 
	}
	for ,  := range  {
		if  := flattenCubic(, [0], [1], [2], [3], , 0, );  != nil {
			return nil, 
		}
	}
	return []subpath{{points: , closed: true}}, nil
}

func flattenQuadratic( context.Context, , ,  d2scene.Point,  float64,  int,  func(d2scene.Point) error) error {
	if  := .Err();  != nil {
		return 
	}
	if pointLineDistance(, , ) <=  && controlsProgress(, , , ) {
		return ()
	}
	if  >= maxCurveDepth {
		return fmt.Errorf("quadratic cannot be flattened within tolerance")
	}
	 := midpoint(, )
	 := midpoint(, )
	 := midpoint(, )
	if  := (, , , , , +1, );  != nil {
		return 
	}
	return (, , , , , +1, )
}

func flattenCubic( context.Context, , , ,  d2scene.Point,  float64,  int,  func(d2scene.Point) error) error {
	if  := .Err();  != nil {
		return 
	}
	if math.Max(pointLineDistance(, , ), pointLineDistance(, , )) <=  &&
		controlsProgress(, , , , ) {
		return ()
	}
	if  >= maxCurveDepth {
		return fmt.Errorf("cubic cannot be flattened within tolerance")
	}
	 := midpoint(, )
	 := midpoint(, )
	 := midpoint(, )
	 := midpoint(, )
	 := midpoint(, )
	 := midpoint(, )
	if  := (, , , , , , +1, );  != nil {
		return 
	}
	return (, , , , , , +1, )
}

func flattenArc( context.Context,  d2scene.Point,  d2scene.PathCommand,  d2scene.Matrix,  float64,  func(d2scene.Point) error) error {
	if  := .Err();  != nil {
		return 
	}
	if !finite() ||  <= 0 {
		return fmt.Errorf("invalid arc flattening tolerance")
	}
	 := .P1
	// SVG endpoint arcs with identical endpoints are omitted. This is distinct
	// from a zero-radius arc, which is a straight line to the endpoint. Still
	// invoke appendPoint: its callback charges the input command before exact
	// duplicate removal, preventing no-op arcs from bypassing path limits.
	if  ==  {
		return ()
	}
	if .RadiusX == 0 || .RadiusY == 0 {
		return ()
	}

	, ,  := d2scene.EndpointArcToCenter(, )
	if  != nil {
		return 
	}
	if ! {
		return ()
	}
	 := .TransformedRadiusBound()
	if !finite() {
		return fmt.Errorf("transformed arc radius is outside the numeric domain")
	}
	return flattenArcInterval(, , .StartAngle(), .StartAngle()+.DeltaAngle(), , , , 0, )
}

// flattenArcInterval uses the linear-interpolation remainder bound
// M*h^2/8. For an affine ellipse the second derivative M is bounded by
// hypot(|u|, |v|), so every emitted chord stays within tolerance without
// depending on a fixed angular sample count.
func flattenArcInterval( context.Context,  d2scene.CenterArc, ,  float64,  d2scene.Point, ,  float64,  int,  func(d2scene.Point) error) error {
	if  := .Err();  != nil {
		return 
	}
	 := math.Abs( - )
	 :=  *  / 8
	if  == 0 ||  <= / {
		return ()
	}
	if  >= maxCurveDepth {
		return fmt.Errorf("arc cannot be flattened within tolerance")
	}
	 :=  + (-)/2
	 := .PointAt()
	if !finitePoint() {
		return fmt.Errorf("arc is outside the numeric domain")
	}
	if  := (, , , , , , , +1, );  != nil {
		return 
	}
	return (, , , , , , , +1, )
}

func pointLineDistance(, ,  d2scene.Point) float64 {
	,  := .X-.X, .Y-.Y
	 := math.Hypot(, )
	if  == 0 {
		return math.Hypot(.X-.X, .Y-.Y)
	}
	return math.Abs(*(.Y-.Y)-(.X-.X)*) / 
}

func controlsProgress(,  d2scene.Point,  float64,  ...d2scene.Point) bool {
	,  := .X-.X, .Y-.Y
	 := math.Hypot(, )
	if  == 0 {
		for ,  := range  {
			if math.Hypot(.X-.X, .Y-.Y) >  {
				return false
			}
		}
		return true
	}
	,  := /, /
	 := 0.0
	for ,  := range  {
		,  := .X-.X, .Y-.Y
		 := * + *
		 := math.Abs(* - *)
		 := 0.0
		if  < 0 {
			 = -
		} else if  >  {
			 =  - 
		}
		// A small projection reversal is harmless only when every control
		// remains inside the tolerance-radius tube around the finite chord.
		// That tube is convex, so it also bounds the complete Bezier. Larger
		// reversals still subdivide to preserve dashes and retraced strokes.
		if !finite() || !finite() || math.Hypot(, ) >  ||  < - {
			return false
		}
		 = 
	}
	return true
}

func midpoint(,  d2scene.Point) d2scene.Point {
	return d2scene.Point{X: (.X + .X) / 2, Y: (.Y + .Y) / 2}
}

func samePoint(,  d2scene.Point) bool {
	return  == 
}

func interpolate(,  d2scene.Point,  float64) d2scene.Point {
	return d2scene.Point{X: .X + (.X-.X)*, Y: .Y + (.Y-.Y)*}
}

func appendDashPoint( []d2scene.Point,  d2scene.Point) []d2scene.Point {
	if len() == 3 && cap() == 3 {
		// Growing a three-point seed normally jumps to capacity six. An exact
		// four-point step keeps cumulative storage equal to the ordinary
		// 1,2,4 growth sequence while retaining the seed's saved allocation.
		 := make([]d2scene.Point, 4)
		copy(, )
		[3] = 
		return 
	}
	return append(, )
}

func drawStroke( context.Context,  *image.RGBA,  []strokeRun,  d2scene.Matrix,  *preparedStroke,  *rasterScratch) error {
	if .paint.kind == preparedSolidPaint {
		 := .reset(.Bounds())
		 := setRasterizerReference(, .Bounds().Min, .referenceBounds.Min, .regionFilters)
		 := d2scene.Translate(-float64(.X), -float64(.Y)).Mul()
		for ,  := range  {
			if  := .Err();  != nil {
				return 
			}
			if  := addStrokeRun(, , , , );  != nil {
				return 
			}
		}
		if  := .DrawRGBA(, .workBudget(), , .paint.solid);  != nil {
			return fmt.Errorf("d2raster: solid stroke: %w", )
		}
		return .Err()
	}

	 := paintedStrokePixelBounds(, , , .Bounds())
	return drawRasterizedPaint(, , , .paint, , "gradient stroke", func( *scanline.Rasterizer) error {
		 := .Min
		if .regionFilters {
			 = paintedStrokePixelBounds(, , , .referenceBounds).Min
		}
		 := setRasterizerReference(, .Min, , .regionFilters)
		 := d2scene.Translate(-float64(.X), -float64(.Y)).Mul()
		for ,  := range  {
			if  := .Err();  != nil {
				return 
			}
			if  := addStrokeRun(, , , , );  != nil {
				return 
			}
		}
		return .Err()
	})
}

func paintedStrokePixelBounds( []strokeRun,  d2scene.Matrix,  *preparedStroke,  image.Rectangle) image.Rectangle {
	return strokeRunPixelBounds(, , strokeExtent(, ), )
}

func strokeExtent( *preparedStroke,  d2scene.Matrix) float64 {
	 := .width * .MaxScale() / 2
	 := 1.0
	if .cap == d2scene.CapSquare {
		 = math.Sqrt2
	}
	if .join == d2scene.JoinMiter && .miterLimit >  {
		 = .miterLimit
	}
	return  * 
}

func strokeRunPixelBounds( []strokeRun,  d2scene.Matrix,  float64,  image.Rectangle) image.Rectangle {
	,  := math.Inf(1), math.Inf(1)
	,  := math.Inf(-1), math.Inf(-1)
	for ,  := range  {
		for ,  := range .points {
			 := .Point()
			 = math.Min(, .X)
			 = math.Min(, .Y)
			 = math.Max(, .X)
			 = math.Max(, .Y)
		}
	}
	if math.IsInf(, 1) {
		return image.Rectangle{}
	}
	// One extra pixel covers vector antialiasing and flattening tolerance.
	++
	,  = -, -
	,  = +, +
	if  < float64(.Min.X) ||  < float64(.Min.Y) ||  > float64(.Max.X) ||  > float64(.Max.Y) {
		return image.Rectangle{}
	}
	 = math.Max(, float64(.Min.X))
	 = math.Max(, float64(.Min.Y))
	 = math.Min(, float64(.Max.X))
	 = math.Min(, float64(.Max.Y))
	return image.Rect(int(math.Floor()), int(math.Floor()), int(math.Ceil()), int(math.Ceil())).Intersect()
}

func makeStrokeRuns( context.Context,  subpath,  []float64,  float64,  func() error) ([]strokeRun, error) {
	 := cleanPoints(.points, .closed)
	if len() < 2 {
		return nil, nil
	}
	if len() == 0 {
		return []strokeRun{{points: , closed: .closed}}, nil
	}

	 := 
	if len()%2 != 0 {
		 = make([]float64, len()*2)
		copy(, )
		copy([len():], )
	}
	 := 0.0
	for ,  := range  {
		 += 
	}
	 := math.Mod(, )
	if  < 0 {
		 += 
	}
	 := 0
	for  >= [] {
		 :=  - []
		if  ==  {
			return nil, fmt.Errorf("dash offset is too large relative to the dash pattern")
		}
		 = 
		 = ( + 1) % len()
	}
	 := [] - 
	 := %2 == 0
	 := 
	var  []strokeRun
	var  []d2scene.Point

	 := len() - 1
	if .closed {
		 = len()
	}
	for  := 0;  < ; ++ {
		if  := .Err();  != nil {
			return nil, 
		}
		 := []
		 :=  + 1
		if  == len() {
			 = 0
		}
		 := []
		,  := .X-.X, .Y-.Y
		 := math.Hypot(, )
		if  == 0 {
			continue
		}
		 := 0.0
		for  <  {
			if  := .Err();  != nil {
				return nil, 
			}
			 :=  - 
			 :=  <= 
			 := 
			if  {
				 = 
			}
			 :=  + 
			if  <=  {
				return nil, fmt.Errorf("dash pattern is below the path's floating-point resolution")
			}
			 := interpolate(, , /)
			 := interpolate(, , /)
			if  {
				if len() == 0 {
					if  := ();  != nil {
						return nil, 
					}
					if samePoint(, ) {
						 = append(, )
					} else {
						if  := ();  != nil {
							return nil, 
						}
						// Nearly every dash run begins with two distinct points.
						// Materialize the pair in one allocation, with room for the
						// common case where the run crosses one path vertex.
						 = make([]d2scene.Point, 2, 3)
						[0], [1] = , 
					}
				} else {
					if !samePoint([len()-1], ) {
						if  := ();  != nil {
							return nil, 
						}
						 = appendDashPoint(, )
					}
					if !samePoint([len()-1], ) {
						if  := ();  != nil {
							return nil, 
						}
						 = appendDashPoint(, )
					}
				}
			}
			 = 
			if  {
				if  && len() >= 2 {
					 = append(, strokeRun{points: })
					 = nil
				}
				 = ( + 1) % len()
				 = %2 == 0
				 = []
			} else {
				 -= 
			}
		}
	}
	if  && len() >= 2 {
		 = append(, strokeRun{points: })
	}
	if !.closed || len() == 0 {
		return , nil
	}

	 := [0]
	 := samePoint([0].points[0], )
	 := &[len()-1]
	 := samePoint(.points[len(.points)-1], )
	if len() == 1 &&  &&  {
		[0].points = [0].points[:len([0].points)-1]
		[0].closed = true
		return , nil
	}
	if  &&  &&  && len() > 1 {
		 := [len()-1].points
		 := [0].points
		 := make([]d2scene.Point, 0, len()+len()-1)
		 = append(, ...)
		 = append(, [1:]...)
		[0] = strokeRun{points: }
		 = [:len()-1]
	}
	return , nil
}

func addStrokeRun( context.Context,  *scanline.Rasterizer,  strokeRun,  d2scene.Matrix,  *preparedStroke) error {
	// makeStrokeRuns canonicalizes every run during preflight, so rendering can
	// use the stored points without allocating another cleaned copy per dash.
	 := .points
	 := .width / 2
	if len() < 2 ||  <= 0 {
		return nil
	}
	 := len() - 1
	if .closed {
		 = len()
	}
	for  := 0;  < ; ++ {
		if  := .Err();  != nil {
			return 
		}
		 := []
		 :=  + 1
		if  == len() {
			 = 0
		}
		 := []
		,  := .X-.X, .Y-.Y
		 := math.Hypot(, )
		if  == 0 {
			continue
		}
		,  := /, /
		if !.closed && .cap == d2scene.CapSquare {
			if  == 0 {
				.X -=  * 
				.Y -=  * 
			}
			if  == -1 {
				.X +=  * 
				.Y +=  * 
			}
		}
		 := d2scene.Point{X: - * , Y:  * }
		addPolygon(, , []d2scene.Point{
			{X: .X + .X, Y: .Y + .Y},
			{X: .X + .X, Y: .Y + .Y},
			{X: .X - .X, Y: .Y - .Y},
			{X: .X - .X, Y: .Y - .Y},
		})
	}

	,  := 1, len()-1
	if .closed {
		,  = 0, len()
	}
	switch .join {
	case d2scene.JoinRound:
		for  := ;  < ; ++ {
			if  := .Err();  != nil {
				return 
			}
			// The union of segment rectangles and a disk at each vertex is
			// the exact round-join outline (the centerline's Minkowski sum).
			addCircle(, , [], )
		}
	case d2scene.JoinMiter, d2scene.JoinBevel:
		 :=  - 1
		if  < 0 {
			 = len() - 1
		}
		,  := unitVector([], [])
		for  := ;  < ; ++ {
			if  := .Err();  != nil {
				return 
			}
			 :=  + 1
			if  == len() {
				 = 0
			}
			 := []
			,  := unitVector(, [])
			var  [4]d2scene.Point
			if  := strokeJoinPolygonFromUnits(&, , , ,  && , , .join, .miterLimit);  != 0 {
				addPolygon(, , [:])
			}
			,  = , 
		}
	}
	if !.closed && .cap == d2scene.CapRound {
		addCircle(, , [0], )
		addCircle(, , [len()-1], )
	}
	return nil
}

// strokeJoinPolygonFromUnits returns the outer wedge missing from the union of the two
// adjacent segment rectangles. A miter over its limit degrades to the same
// three-point bevel wedge. Geometry is built in local coordinates so an affine
// transform, including a nonuniform one, affects the complete stroke outline.
func strokeJoinPolygonFromUnits( *[4]d2scene.Point, , ,  d2scene.Point,  bool,  float64,  d2scene.LineJoin,  float64) int {
	if ! {
		return 0
	}
	 := crossProduct(, )
	if math.Abs() <= geometryEpsilon {
		// A straight continuation needs no join. A reversal has no stable
		// outer side; the two butt-ended segment rectangles are the safe
		// finite bevel result.
		return 0
	}
	 := 1.0
	if  > 0 {
		 = -1
	}
	 := d2scene.Point{X: -.Y *  * , Y: .X *  * }
	 := d2scene.Point{X: -.Y *  * , Y: .X *  * }
	 := d2scene.Point{X: .X + .X, Y: .Y + .Y}
	 := d2scene.Point{X: .X + .X, Y: .Y + .Y}
	[0], [1], [2] = , , 
	if  != d2scene.JoinMiter {
		return 3
	}

	 := crossProduct(, )
	 := d2scene.Point{X: .X - .X, Y: .Y - .Y}
	 := crossProduct(, ) / 
	 := d2scene.Point{
		X: .X + *.X,
		Y: .Y + *.Y,
	}
	 := math.Hypot(.X-.X, .Y-.Y)
	 :=  / 
	if !finitePoint() || !finite() ||  >  {
		return 3
	}
	[0], [1], [2], [3] = , , , 
	return 4
}

func unitVector(,  d2scene.Point) (d2scene.Point, bool) {
	,  := .X-.X, .Y-.Y
	 := math.Hypot(, )
	if !finite() ||  == 0 {
		return d2scene.Point{}, false
	}
	return d2scene.Point{X:  / , Y:  / }, true
}

func crossProduct(,  d2scene.Point) float64 {
	return .X*.Y - .Y*.X
}

func addPolygon( *scanline.Rasterizer,  d2scene.Matrix,  []d2scene.Point) {
	if len() < 3 {
		return
	}
	 := transformedPolygonSignedArea2(, )
	if  == 0 || !finite() {
		return
	}
	// Segment rectangles and round disks have negative local winding. Preserve
	// that sign through reflections so every union component accumulates rather
	// than cancelling its neighbors under non-zero rasterization.
	 := .Determinant() >= 0
	 := ( < 0) != 
	 := 0
	if  {
		 = len() - 1
	}
	 := .Point([])
	.MoveTo64(.X, .Y)
	if  {
		for  := len() - 2;  >= 0; -- {
			 := .Point([])
			.LineTo64(.X, .Y)
		}
	} else {
		for ,  := range [1:] {
			 := .Point()
			.LineTo64(.X, .Y)
		}
	}
	.ClosePath()
}

func transformedPolygonSignedArea2( []d2scene.Point,  d2scene.Matrix) float64 {
	if len() < 3 {
		return 0
	}
	 := .Point([0])
	 := 0.0
	for  := 1; +1 < len(); ++ {
		 := .Point([])
		 := .Point([+1])
		 := d2scene.Point{X: .X - .X, Y: .Y - .Y}
		 := d2scene.Point{X: .X - .X, Y: .Y - .Y}
		 += crossProduct(, )
	}
	return 
}

func addCircle( *scanline.Rasterizer,  d2scene.Matrix,  d2scene.Point,  float64) {
	// The circle winding matches addPolygon so overlapping stroke components
	// form a non-zero union instead of cancelling one another.
	 := 0.5522847498307936 * 
	 := .Point(d2scene.Point{X: .X + , Y: .Y})
	.MoveTo64(.X, .Y)
	 := .Point(d2scene.Point{X: .X + , Y: .Y - })
	 := .Point(d2scene.Point{X: .X + , Y: .Y - })
	 := .Point(d2scene.Point{X: .X, Y: .Y - })
	.CubeTo64(.X, .Y, .X, .Y, .X, .Y)
	 = .Point(d2scene.Point{X: .X - , Y: .Y - })
	 = .Point(d2scene.Point{X: .X - , Y: .Y - })
	 = .Point(d2scene.Point{X: .X - , Y: .Y})
	.CubeTo64(.X, .Y, .X, .Y, .X, .Y)
	 = .Point(d2scene.Point{X: .X - , Y: .Y + })
	 = .Point(d2scene.Point{X: .X - , Y: .Y + })
	 = .Point(d2scene.Point{X: .X, Y: .Y + })
	.CubeTo64(.X, .Y, .X, .Y, .X, .Y)
	 = .Point(d2scene.Point{X: .X + , Y: .Y + })
	 = .Point(d2scene.Point{X: .X + , Y: .Y + })
	 = .Point(d2scene.Point{X: .X + , Y: .Y})
	.CubeTo64(.X, .Y, .X, .Y, .X, .Y)
	.ClosePath()
}

func cleanPoints( []d2scene.Point,  bool) []d2scene.Point {
	 := -1
	for  := 1;  < len(); ++ {
		if samePoint([-1], []) {
			 = 
			break
		}
	}
	if  < 0 {
		if  && len() > 1 && samePoint([0], [len()-1]) {
			return [:len()-1]
		}
		return 
	}

	 := make([]d2scene.Point, 0, len())
	 = append(, [:]...)
	for ,  := range [:] {
		if len() == 0 || !samePoint([len()-1], ) {
			 = append(, )
		}
	}
	if  && len() > 1 && samePoint([0], [len()-1]) {
		 = [:len()-1]
	}
	return 
}