diff --git a/experiments/rounded_rect.nim b/experiments/rounded_rect.nim
new file mode 100644
index 0000000..8313e3a
--- /dev/null
+++ b/experiments/rounded_rect.nim
@@ -0,0 +1,123 @@
+import benchy, chroma, pixie, pixie/internal, strformat
+import benchy, chroma, pixie
+
+proc newRoundedRectImage1(w, h, r: int, color: Color): Image =
+  result = newImage(w, h)
+  let ctx = newContext(result)
+  ctx.fillStyle = color(0, 1, 0, 1)
+  let
+    pos = vec2(0, 0)
+    wh = vec2(w.float32, h.float32)
+    r = r.float32
+  ctx.fillRoundedRect(rect(pos, wh), r)
+
+proc newRoundedRectImage15(w, h, r: int, color: Color): Image =
+  let path = newPath()
+  let
+    pos = vec2(0, 0)
+    wh = vec2(w.float32, h.float32)
+    r = r.float32
+  path.roundedRect(rect(pos, wh), r, r, r, r)
+  result = path.fillImage(w, h, color(0, 1, 0, 1))
+
+proc newRoundedRectImage2(w, h, r: int, color: Color): Image =
+  result = newImage(w, h)
+  result.fill(color)
+
+  let
+    w1 = w - 1
+    h1 = h - 1
+  for y in 0 ..< r:
+    for x in 0 ..< r:
+      var a: float32 = 0
+      for s in 0 ..< 5:
+        let
+          yc = y.float32 + s.float32 / 5 + (1 / 5 / 2)
+          xc = r.float32 - sqrt(r.float32*r.float32 - (yc - r.float32) ^ 2)
+        let mid = (x.float32 - xc + 1).clamp(0, 1)
+        a += 1/5 * mid
+
+      if a < 1:
+        var c = color
+        c.a = a
+        let cx = c.rgbx
+        result.setRgbaUnsafe(x, y, cx)
+        result.setRgbaUnsafe(w1 - x, y, cx)
+        result.setRgbaUnsafe(w1 - x, h1 - y, cx)
+        result.setRgbaUnsafe(x, h1 - y, cx)
+
+proc newRoundedRectImage3(w, h, r: int, color: Color): Image =
+  result = newImage(w, h)
+  result.fill(color)
+
+  if r == 0:
+    return
+
+  const
+    q = 5
+    qf = q.float32
+    qoffset: float32 = (1 / qf / 2)
+
+  let
+    r = r.clamp(0, min(w, h) div 2)
+    rf = r.float32
+    w1 = w - 1
+    h1 = h - 1
+    rgbx = color.rgbx
+    channels = [rgbx.r.uint32, rgbx.g.uint32, rgbx.b.uint32, rgbx.a.uint32]
+
+  var coverage = newSeq[uint8](r)
+
+  for y in 0 ..< r:
+    zeroMem(coverage[0].addr, coverage.len)
+    var yf: float32 = y.float32 + qoffset
+    for m in 0 ..< q:
+      let hit = sqrt(rf^2 - yf^2)
+      coverage[hit.int] += max((1 - (hit - hit.trunc)) * 255 / qf, 0).uint8
+      for x in hit.int + 1 ..< r:
+        coverage[x] += (255 div q).uint8
+      yf += 1 / qf
+
+    for x in 0 ..< r:
+      let coverage = 255 - coverage[x]
+      if coverage != 255:
+        var cx: ColorRGBX
+        cx.r = ((channels[0] * coverage) div 255).uint8
+        cx.g = ((channels[1] * coverage) div 255).uint8
+        cx.b = ((channels[2] * coverage) div 255).uint8
+        cx.a = ((channels[3] * coverage) div 255).uint8
+
+        let
+          xn = r - x - 1
+          yn = r - y - 1
+        result.setRgbaUnsafe(xn, yn, cx)
+        result.setRgbaUnsafe(w1 - xn, yn, cx)
+        result.setRgbaUnsafe(w1 - xn, h1 - yn, cx)
+        result.setRgbaUnsafe(xn, h1 - yn, cx)
+
+const r = 16
+
+let img1 = newRoundedRectImage1(200, 200, r, color(0, 1, 0, 1))
+img1.writeFile("rrect_current.png")
+let img2 = newRoundedRectImage3(200, 200, r, color(0, 1, 0, 1))
+img2.writeFile("rrect_new.png")
+
+let (diffScore, diffImage) = diff(img1, img2)
+echo &"score: {diffScore}"
+diffImage.writeFile("rrect_diff.png")
+
+timeIt "fill rounded rect via path 1":
+  for i in 0 ..< 10:
+    discard newRoundedRectImage1(200, 200, r, color(0, 1, 0, 1))
+
+timeIt "fill rounded rect via path 1.5":
+  for i in 0 ..< 10:
+    discard newRoundedRectImage15(200, 200, r, color(0, 1, 0, 1))
+
+timeIt "fill rounded rect via math 2":
+  for i in 0 ..< 10:
+    discard newRoundedRectImage2(200, 200, 50, color(0, 1, 0, 1))
+
+timeIt "fill rounded rect via math 3":
+  for i in 0 ..< 10:
+    discard newRoundedRectImage3(200, 200, r, color(0, 1, 0, 1))
diff --git a/experiments/sweeps3.nim b/experiments/sweeps3.nim
index 655783e..6d81fbd 100644
--- a/experiments/sweeps3.nim
+++ b/experiments/sweeps3.nim
@@ -64,6 +64,10 @@ var hourGlass = parsePath("""
   M 20 20 L 180 20 L 20 180 L 180 180 z
 """)
 
+var hourGlass2 = parsePath("""
+  M 20 20 L 180 20 L 20 180 L 180 180 z M 62 24 L 132 24 L 50 173 L 156 173 z
+""")
+
 # Hole
 var hole = parsePath("""
   M 40 40 L 40 160 L 160 160 L 160 40 z
@@ -88,6 +92,8 @@ when defined(bench):
   test("cricle", cricle, 100)
   test("halfAarc", halfAarc, 100)
   test("hourGlass", hourGlass, 100)
+  test("hourGlass2", hourGlass2, wr=wrNonZero)
+  test("hourGlass2", hourGlass2, wr=wrEvenOdd)
   test("hole", hole, 100)
   test("holeEvenOdd", holeEvenOdd, 100, wr=wrNonZero)
   test("holeEvenOdd", holeEvenOdd, 100, wr=wrEvenOdd)
@@ -99,7 +105,8 @@ else:
   # test("cricle", cricle)
   # test("halfAarc", halfAarc)
   # test("hourGlass", hourGlass)
-  #test("hole", hole, wr=wrEvenOdd)
-  test("holeEvenOdd", holeEvenOdd, wr=wrNonZero)
-  test("holeEvenOdd", holeEvenOdd, wr=wrEvenOdd)
+  test("hourGlass2", hourGlass2, wr=wrEvenOdd)
+  # test("hole", hole, wr=wrEvenOdd)
+  # test("holeEvenOdd", holeEvenOdd, wr=wrNonZero)
+  # test("holeEvenOdd", holeEvenOdd, wr=wrEvenOdd)
   # test("letterG", letterG)
diff --git a/experiments/trapezoids/output_sweep.png b/experiments/trapezoids/output_sweep.png
index 4835f2d..516a83a 100644
Binary files a/experiments/trapezoids/output_sweep.png and b/experiments/trapezoids/output_sweep.png differ
diff --git a/src/pixie/fileformats/svg.nim b/src/pixie/fileformats/svg.nim
index f786db8..293d3a2 100644
--- a/src/pixie/fileformats/svg.nim
+++ b/src/pixie/fileformats/svg.nim
@@ -2,6 +2,7 @@
 
 import chroma, pixie/common, pixie/images, pixie/internal, pixie/paints,
     pixie/paths, strutils, tables, vmath, xmlparser, xmltree
+
 when defined(pixieDebugSvg):
   import strtabs
 
diff --git a/src/pixie/paths.nim b/src/pixie/paths.nim
index 4aa032a..acca6bb 100644
--- a/src/pixie/paths.nim
+++ b/src/pixie/paths.nim
@@ -2103,6 +2103,17 @@ when defined(pixieSweeps):
     line.winding = s[1]
     return line
 
+  proc intersectsYLine(y: float32, s: Segment, atx: var float32): bool {.inline.} =
+    let
+      s2y = s.to.y - s.at.y
+      denominator = -s2y
+      numerator = s.at.y - y
+      u = numerator / denominator
+    if u >= 0 and u <= 1:
+      let at = s.at + (u * vec2(s.to.x - s.at.x, s2y))
+      atx = at.x
+      return true
+
   proc binaryInsert(arr: var seq[float32], v: float32) =
     if arr.len == 0:
       arr.add(v)
@@ -2195,16 +2206,23 @@ when defined(pixieSweeps):
     windingRule: WindingRule,
     blendMode: BlendMode
   ) =
-    const q = 1/256.0
+
     let rgbx = color.rgbx
     var segments = shapes.shapesToSegments()
     let
       bounds = computeBounds(segments).snapToPixels()
       startX = max(0, bounds.x.int)
 
-    if segments.len == 0:
+    if segments.len == 0 or bounds.w.int == 0 or bounds.h.int == 0:
       return
 
+    # const q = 1/10
+    # for i in 0 ..< segments.len:
+    #   segments[i][0].at.x = quantize(segments[i][0].at.x, q)
+    #   segments[i][0].at.y = quantize(segments[i][0].at.y, q)
+    #   segments[i][0].to.x = quantize(segments[i][0].to.x, q)
+    #   segments[i][0].to.y = quantize(segments[i][0].to.y, q)
+
     # Create sorted segments.
     segments.sortSegments(0, segments.high)
 
@@ -2227,14 +2245,13 @@ when defined(pixieSweeps):
           let s = segments[lastSeg]
 
           if s[0].to.y != cutLines[i + 1]:
-            var at: Vec2
+            var atx: float32
             var seg = s[0]
             for j in i ..< sweeps.len:
               let y = cutLines[j + 1]
-              #TODO: speed up with horizintal line intersect
-              if intersects(line(vec2(0, y), vec2(1, y)), seg, at):
-                sweeps[j].add(toLine((segment(seg.at, at), s[1])))
-                seg = segment(at, seg.to)
+              if intersectsYLine(y, seg, atx):
+                sweeps[j].add(toLine((segment(seg.at, vec2(atx, y)), s[1])))
+                seg = segment(vec2(atx, y), seg.to)
               else:
                 if seg.at.y != seg.to.y:
                   sweeps[j].add(toLine(s))
@@ -2247,40 +2264,49 @@ when defined(pixieSweeps):
             break
       inc i
 
-    i = 0
-    while i < sweeps.len:
-      # TODO: Maybe finds all cuts first, add them to array, cut all lines at once.
-      for t in 0 ..< 10: # TODO: maybe while true:
-        # keep cutting sweep
-        var needsCut = false
-        var cutterLine: float32 = 0
-        block doubleFor:
-          for a in sweeps[i]:
-            let aSeg = segment(vec2(a.atx, cutLines[i]), vec2(a.tox, cutLines[i+1]))
-            for b in sweeps[i]:
-              let bSeg = segment(vec2(b.atx, cutLines[i]), vec2(b.tox, cutLines[i+1]))
-              var at: Vec2
-              if intersectsInner(aSeg, bSeg, at):
-                needsCut = true
-                cutterLine = at.y
-                break doubleFor
-        # TODO enable?
-        if false and needsCut:
-          # Doing a cut.
-          var
-            thisSweep = sweeps[i]
-          sweeps[i].setLen(0)
-          sweeps.insert(newSeq[SweepLine](), i + 1)
-          for a in thisSweep:
-            let seg = segment(vec2(a.atx, cutLines[i]), vec2(a.tox, cutLines[i+1]))
-            var at: Vec2
-            if intersects(line(vec2(0, cutterLine), vec2(1, cutterLine)), seg, at):
-              sweeps[i+0].add(toLine((segment(seg.at, at), a.winding)))
-              sweeps[i+1].add(toLine((segment(at, seg.to), a.winding)))
-          cutLines.binaryInsert(cutterLine)
-        else:
-          break
-      inc i
+    # i = 0
+    # while i < sweeps.len:
+    #   # TODO: Maybe finds all cuts first, add them to array, cut all lines at once.
+    #   var crossCuts: seq[float32]
+
+    #   # echo i, " cut?"
+
+    #   for aIndex in 0 ..< sweeps[i].len:
+    #     let a = sweeps[i][aIndex]
+    #     # echo i, ":", sweeps.len, ":", cutLines.len
+    #     let aSeg = segment(vec2(a.atx, cutLines[i]), vec2(a.tox, cutLines[i+1]))
+    #     for bIndex in aIndex + 1 ..< sweeps[i].len:
+    #       let b = sweeps[i][bIndex]
+    #       let bSeg = segment(vec2(b.atx, cutLines[i]), vec2(b.tox, cutLines[i+1]))
+    #       var at: Vec2
+    #       if intersectsInner(aSeg, bSeg, at):
+    #         crossCuts.binaryInsert(at.y)
+
+    #   if crossCuts.len > 0:
+    #     var
+    #       thisSweep = sweeps[i]
+    #       yTop = cutLines[i]
+    #       yBottom = cutLines[i + 1]
+    #     sweeps[i].setLen(0)
+
+    #     for k in crossCuts:
+    #       let prevLen = cutLines.len
+    #       cutLines.binaryInsert(k)
+    #       if prevLen != cutLines.len:
+    #         sweeps.insert(newSeq[SweepLine](), i + 1)
+
+    #     for a in thisSweep:
+    #       var seg = segment(vec2(a.atx, yTop), vec2(a.tox, yBottom))
+    #       var at: Vec2
+    #       for j, cutterLine in crossCuts:
+    #         if intersects(line(vec2(0, cutterLine), vec2(1, cutterLine)), seg, at):
+    #           sweeps[i+j].add(toLine((segment(seg.at, at), a.winding)))
+    #           seg = segment(at, seg.to)
+    #       sweeps[i+crossCuts.len].add(toLine((seg, a.winding)))
+
+    #     i += crossCuts.len
+
+    #   inc i
 
     i = 0
     while i < sweeps.len:
@@ -2320,13 +2346,18 @@ when defined(pixieSweeps):
     #     echo "L ", sw.x, " ", sw.y
 
     proc computeCoverage(
-      coverages: var seq[uint8],
+      coverages: var seq[uint16],
       y: int,
       startX: int,
       cutLines: seq[float32],
       currCutLine: int,
       sweep: seq[SweepLine]
     ) =
+
+      if cutLines[currCutLine + 1] - cutLines[currCutLine] < 1/256:
+        # TODO some thing about micro sweeps
+        return
+
       let
         sweepHeight = cutLines[currCutLine + 1] - cutLines[currCutLine]
         yFracTop = ((y.float32 - cutLines[currCutLine]) / sweepHeight).clamp(0, 1)
@@ -2341,59 +2372,67 @@ when defined(pixieSweeps):
           swX = mix(sweep[i+0].atx, sweep[i+0].tox, yFracBottom)
           seX = mix(sweep[i+1].atx, sweep[i+1].tox, yFracBottom)
 
-          minWi = min(nwX, swX).int
-          maxWi = max(nwX, swX).ceil.int
+          minWi = min(nwX, swX).int#.clamp(startX, coverages.len + startX)
+          maxWi = max(nwX, swX).ceil.int#.clamp(startX, coverages.len + startX)
 
-          minEi = min(neX, seX).int
-          maxEi = max(neX, seX).ceil.int
-
-        # TODO: Add case when trapezoids both starts and stops on same pixle.
+          minEi = min(neX, seX).int#.clamp(startX, coverages.len + startX)
+          maxEi = max(neX, seX).ceil.int#.clamp(startX, coverages.len + startX)
 
         let
           nw = vec2(sweep[i+0].atx, cutLines[currCutLine])
           sw = vec2(sweep[i+0].tox, cutLines[currCutLine + 1])
+          f16 = (256 * 256 - 1).float32
         for x in minWi ..< maxWi:
-          var area = pixelCover(nw - vec2(x.float32, y.float32), sw - vec2(
-              x.float32, y.float32))
-          coverages[x - startX] += (area * 255).uint8
+          var area = pixelCover(
+            nw - vec2(x.float32, y.float32),
+            sw - vec2(x.float32, y.float32)
+          )
+          coverages[x - startX] += (area * f16).uint16
 
         let x = maxWi
-        var midArea = pixelCover(nw - vec2(x.float32, y.float32), sw - vec2(
-            x.float32, y.float32))
-        var midArea8 = (midArea * 255).uint8
-        for x in maxWi ..< minEi:
-          # TODO: Maybe try coverages of uint16 to prevent streeks in solid white fill?
-          coverages[x - startX] += midArea8
+        var midArea = pixelCover(
+          nw - vec2(x.float32, y.float32),
+          sw - vec2(x.float32, y.float32)
+        )
+        for x in maxWi ..< maxEi:
+          coverages[x - startX] += (midArea * f16).uint16
 
         let
           ne = vec2(sweep[i+1].atx, cutLines[currCutLine])
           se = vec2(sweep[i+1].tox, cutLines[currCutLine + 1])
         for x in minEi ..< maxEi:
-          var area = midArea - pixelCover(ne - vec2(x.float32, y.float32), se -
-              vec2(x.float32, y.float32))
-          coverages[x - startX] += (area * 255).uint8
+          var area = pixelCover(
+            ne - vec2(x.float32, y.float32),
+            se - vec2(x.float32, y.float32)
+          )
+          coverages[x - startX] -= (area * f16).uint16
 
         i += 2
 
     var
       currCutLine = 0
-      coverages = newSeq[uint8](bounds.w.int)
-    for scanLine in cutLines[0].int ..< cutLines[^1].ceil.int:
-      zeroMem(coverages[0].addr, coverages.len)
+      coverages16 = newSeq[uint16](bounds.w.int)
+      coverages8 = newSeq[uint8](bounds.w.int)
+    for scanLine in max(cutLines[0].int, 0) ..< min(cutLines[^1].ceil.int, image.height):
 
-      coverages.computeCoverage(scanLine, startX, cutLines, currCutLine, sweeps[currCutLine])
+      zeroMem(coverages16[0].addr, coverages16.len * 2)
+
+      coverages16.computeCoverage(
+        scanLine, startX, cutLines, currCutLine, sweeps[currCutLine])
       while cutLines[currCutLine + 1] < scanLine.float + 1.0:
         inc currCutLine
         if currCutLine == sweeps.len:
           break
-        coverages.computeCoverage(scanLine, startX, cutLines, currCutLine,
-            sweeps[currCutLine])
+        coverages16.computeCoverage(
+          scanLine, startX, cutLines, currCutLine, sweeps[currCutLine])
 
+      for i in 0 ..< coverages16.len:
+        coverages8[i] = (coverages16[i] shr 8).uint8
       image.fillCoverage(
         rgbx,
         startX = startX,
         y = scanLine,
-        coverages,
+        coverages8,
         blendMode
       )