I am creating a pixel art editor for Android, and recently I implemented an ellipse tool using the midpoint ellipse algorithm.
I would just like to emphasize that this tool works perfectly!
The only problem is, if I draw a large ellipse on a larger bitmap (of around 1000x1000 or more), the sides of the ellipse get cut, and there is some strange behaviour going on:
I am really confused why this is happening, and I would appreciate help.
Code for the midpoint ellipse algorithm:
package com.therealbluepandabear.pixapencil.algorithms
import com.therealbluepandabear.pixapencil.activities.canvas.canvascommands.overrideSetPixel
import com.therealbluepandabear.pixapencil.models.Coordinates
class MidpointEllipseAlgorithm(private val algorithmInfo: AlgorithmInfoParameter, private val xDEC: Boolean = false, private val yDEC: Boolean = false, private val filledMode: Boolean = false) {
private val shouldLineIgnoreBrush = true
private fun putPixel(p1: Coordinates, p2: Coordinates) {
val xc = p1.x
val yc = p1.y
val x = p2.x
val y = p2.y
if (!xDEC && !yDEC) {
algorithmInfo.canvasCommandsHelperInstance.overrideSetPixel(
Coordinates(xc x, yc y),
algorithmInfo.color
)
algorithmInfo.canvasCommandsHelperInstance.overrideSetPixel(
Coordinates(xc x, yc - y),
algorithmInfo.color
)
algorithmInfo.canvasCommandsHelperInstance.overrideSetPixel(
Coordinates(xc - x, yc - y),
algorithmInfo.color
)
algorithmInfo.canvasCommandsHelperInstance.overrideSetPixel(
Coordinates(xc - x, yc y),
algorithmInfo.color
)
if (filledMode) {
val lineAlgorithmInstance = LineAlgorithm(algorithmInfo, shouldLineIgnoreBrush)
lineAlgorithmInstance.compute(
Coordinates(xc x, yc y),
Coordinates(xc x, yc - y),
)
lineAlgorithmInstance.compute(
Coordinates(xc - x, yc - y),
Coordinates(xc - x, yc y),
)
}
} else if (xDEC && !yDEC) {
algorithmInfo.canvasCommandsHelperInstance.overrideSetPixel(
Coordinates((xc x) 1, yc y),
algorithmInfo.color
)
algorithmInfo.canvasCommandsHelperInstance.overrideSetPixel(
Coordinates((xc x) 1, yc - y),
algorithmInfo.color
)
algorithmInfo.canvasCommandsHelperInstance.overrideSetPixel(
Coordinates(xc - x, yc - y),
algorithmInfo.color
)
algorithmInfo.canvasCommandsHelperInstance.overrideSetPixel(
Coordinates(xc - x, yc y),
algorithmInfo.color
)
if (filledMode) {
val lineAlgorithmInstance = LineAlgorithm(algorithmInfo, shouldLineIgnoreBrush)
lineAlgorithmInstance.compute(
Coordinates((xc x) 1, yc y),
Coordinates((xc x) 1, yc - y),
)
lineAlgorithmInstance.compute(
Coordinates(xc - x, yc - y),
Coordinates(xc - x, yc y),
)
}
} else if (!xDEC && yDEC) {
algorithmInfo.canvasCommandsHelperInstance.overrideSetPixel(
Coordinates(xc x, (yc y) 1),
algorithmInfo.color
)
algorithmInfo.canvasCommandsHelperInstance.overrideSetPixel(
Coordinates(xc x, yc - y),
algorithmInfo.color
)
algorithmInfo.canvasCommandsHelperInstance.overrideSetPixel(
Coordinates(xc - x, yc - y),
algorithmInfo.color
)
algorithmInfo.canvasCommandsHelperInstance.overrideSetPixel(
Coordinates(xc - x, (yc y) 1),
algorithmInfo.color
)
if (filledMode) {
val lineAlgorithmInstance = LineAlgorithm(algorithmInfo, shouldLineIgnoreBrush)
lineAlgorithmInstance.compute(
Coordinates(xc x, (yc y) 1),
Coordinates(xc x, yc - y),
)
lineAlgorithmInstance.compute(
Coordinates(xc - x, yc - y),
Coordinates(xc - x, (yc y) 1),
)
}
} else {
algorithmInfo.canvasCommandsHelperInstance.overrideSetPixel(
Coordinates((xc x) 1, (yc y) 1),
algorithmInfo.color
)
algorithmInfo.canvasCommandsHelperInstance.overrideSetPixel(
Coordinates((xc x) 1, yc - y),
algorithmInfo.color
)
algorithmInfo.canvasCommandsHelperInstance.overrideSetPixel(
Coordinates(xc - x, yc - y),
algorithmInfo.color
)
algorithmInfo.canvasCommandsHelperInstance.overrideSetPixel(
Coordinates(xc - x, (yc y) 1),
algorithmInfo.color
)
if (filledMode) {
val lineAlgorithmInstance = LineAlgorithm(algorithmInfo, shouldLineIgnoreBrush)
lineAlgorithmInstance.compute(
Coordinates((xc x) 1, (yc y) 1),
Coordinates((xc x) 1, yc - y),
)
lineAlgorithmInstance.compute(
Coordinates(xc - x, yc - y),
Coordinates(xc - x, (yc y) 1),
)
}
}
}
fun compute(p1: Coordinates, rx: Int, ry: Int) {
val idp = Coordinates(0, ry)
var xkp1 = idp.x
var ykp1 = idp.y
var lxkp1: Int
var lykp1: Int
var p1k = (ry * ry) ((rx * rx) / 4) - (ry * (rx * rx))
val incy = p1.y
val incx = p1.x
putPixel(Coordinates(incx, incy), Coordinates(xkp1, ykp1))
while (
(2 * (xkp1 1) * (ry * ry))
<
(2 * ykp1 * (rx * rx))
) {
p1k = if (p1k >= 0) {
xkp1
ykp1--
lxkp1 = xkp1 - 1
lykp1 = ykp1 1
(ry * ry) (2 * (lxkp1 1)) * (ry * ry) (rx * rx) * ((ykp1 * ykp1) - (lykp1 * lykp1)) - (rx * rx) * (ykp1 - lykp1)
} else {
xkp1
lxkp1 = xkp1 - 1
lykp1 = ykp1
(ry * ry) (2 * (lxkp1 1)) * (ry * ry) (rx * rx) * ((ykp1 * ykp1) - (lykp1 * lykp1))
}
putPixel(Coordinates(incx, incy), Coordinates(xkp1, ykp1))
}
var p2k = (ry * ry) * ((xkp1 0.5) * (xkp1 0.5)) (rx * rx) * ((ykp1 - 1) * (ykp1 - 1)) - ((rx * rx) * (ry * ry))
while (
ykp1 > 0
) {
if (p2k >= 0) {
ykp1--
lykp1 = ykp1 1
lxkp1 = xkp1
p2k = (rx * rx) - 2 * (rx * rx) * (lykp1 - 1) (ry * ry) * ((xkp1 * xkp1) - (lxkp1 * lxkp1))
} else {
xkp1
lxkp1 = xkp1 - 1
ykp1--
lykp1 = ykp1 1
p2k = (rx * rx) - 2 * (rx * rx) * (lykp1 - 1) (ry * ry) * ((xkp1 * xkp1) - (lxkp1 * lxkp1)) (ry * ry) * (xkp1 - lxkp1)
}
putPixel(Coordinates(incx, incy), Coordinates(xkp1, ykp1))
}
}
}
The problem only exists in the MidpointEllipseAlgorithm
, so it's been isolated. The overrideSetPixel
function is not causing this behaviour because when I replace it with a simple Bitmap.setPixel
the problem still exists. But, although it's been isolated, I am confused why this is happening.
If you draw the ellipse on smaller canvases this behaviour isn't getting demonstrated, it works perfectly. It's only if you draw an ellipse of a sufficient size on a large bitmap where this behaviour is demonstrated.
Any help or directions as to why it's being 'cut' like this on large bitmaps would be appreciated. It's one of those issues where you have absolutely no clue why it's happening, it's completely nonsensical as the algorithm itself has been reviewed by my peers and it is to a high standard. I have tried for a couple of hours to fix it by adjusting variables and inequalities but I have no clue where it's coming from, I even compared my algorithm code to the ones online and still, even if I replace it I get the issue.
CodePudding user response:
Fixed by converting the following to double
:
var p2k = (ry.toDouble() * ry.toDouble()) * ((xkp1.toDouble() 0.5) * (xkp1.toDouble() 0.5)) (rx.toDouble() * rx.toDouble()) * ((ykp1.toDouble() - 1) * (ykp1.toDouble() - 1)) - ((rx.toDouble() * rx.toDouble()) * (ry.toDouble() * ry.toDouble()))