Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Bug report: Strokes of primitive shapes are drawn differently compared to contours #300

Open
Vechro opened this issue May 12, 2022 · 1 comment
Labels
bug Something isn't working

Comments

@Vechro
Copy link
Contributor

Vechro commented May 12, 2022

Operating System

Windows

OPENRNDR version

32ae9e9

Java version

Adoptium 17

Describe the Bug

Currently, OPENRNDR is a bit inconsistent when it comes to strokes. This is most apparent when using a semi-transparent stroke color.

When drawing a Rectangle the stroke is drawn over the fill (top-left shape in the screenshot).
When drawing a Circle the stroke is drawn outside the fill (bottom-left shape in the screenshot).
When drawing a ShapeContour of any kind, the stroke is drawn half-over the fill, leaving the other half outside the fill (top-right and bottom-right shapes in the screenshot).
What's more is that Rectangle and Circle are automatically adjusted as to not change their pixels-on-the-screen size when strokeWeight changes, but this is not the case for ShapeContour, where the strokeWeight affects the pixels-on-the-screen size of the shape. This means calling .contour on a Circle and drawing it can create a shape different in size compared to the original Circle (in terms of pixels on the screen).

I believe the ShapeContour currently has the ideal outcome here, as this matches the behavior of strokes in frameworks such as Processing and is most likely how users expect stroke to work. Therefore the drawing of Rectangle and Circle should be changed to be consistent with ShapeContour.

Steps to Reproduce

import org.openrndr.application
import org.openrndr.color.ColorRGBa
import org.openrndr.draw.isolated
import org.openrndr.shape.Circle
import org.openrndr.shape.Rectangle

fun main() = application {
    configure {
        width = 640
        height = 640
    }

    program {
        backgroundColor = ColorRGBa.WHITE
        val rect = Rectangle(0.0, 0.0, 200.0, 200.0)
        val circle = Circle(0.0, 0.0, 100.0)

        extend {
            drawer.strokeWeight = 8.0
            drawer.fill = ColorRGBa.PINK
            drawer.stroke = ColorRGBa.BLACK.opacify(0.5)

            drawer.isolated {
                drawer.translate(100.0, 100.0)
                drawer.rectangle(rect)

                drawer.translate(210.0, 0.0)
                drawer.contour(rect.contour)
            }
            drawer.isolated {
                drawer.translate(200.0, 410.0)
                drawer.circle(circle)

                drawer.translate(210.0, 0.0)
                drawer.contour(circle.contour)
            }
        }
    }
}

Screenshots (Optional)

image

@Vechro Vechro added the bug Something isn't working label May 12, 2022
@Vechro
Copy link
Contributor Author

Vechro commented Jul 4, 2022

I'll include a more thorough test case that puts more emphasis on correct transparency.
Ideally in this screenshot every quadrant would have 2 pairs of identical shapes.
image

import org.openrndr.application
import org.openrndr.color.ColorRGBa
import org.openrndr.draw.Drawer
import org.openrndr.draw.isolated
import org.openrndr.math.Vector2
import org.openrndr.shape.Circle
import org.openrndr.shape.Rectangle
import org.openrndr.shape.Segment

const val SIZE = 850.0

fun main() = application {
    configure {
        width = SIZE.toInt()
        height = SIZE.toInt()
    }

    val grid = buildList {
        generateSequence(5.0, 10.0::plus)
            .takeWhile { it < SIZE }
            .forEach {
                add(Segment(Vector2(it, 0.0), Vector2(it, SIZE)))
                add(Segment(Vector2(0.0, it), Vector2(SIZE, it)))
            }
    }

    val rect = Rectangle(0.0, 0.0, 200.0, 200.0)
    val circle = Circle(0.0, 0.0, 100.0)

    fun drawTestShapes(drawer: Drawer) {
        drawer.translate(10.0, 10.0)
        drawer.rectangle(rect)
        drawer.translate(210.0, 0.0)
        drawer.contour(rect.contour)
        drawer.translate(-110.0, 310.0)
        drawer.circle(circle)
        drawer.translate(210.0, 0.0)
        drawer.contour(circle.contour)
    }

    program {
        backgroundColor = ColorRGBa.WHITE

        extend {
            drawer.strokeWeight = 0.1
            drawer.stroke = ColorRGBa.BLACK
            drawer.segments(grid)
        }

        extend {
            drawer.strokeWeight = 10.0

            drawer.isolated {
                drawer.stroke = ColorRGBa.BLACK.opacify(0.5)
                drawer.fill = ColorRGBa.PINK
                drawTestShapes(this)
            }
            drawer.isolated {
                drawer.stroke = ColorRGBa.BLACK.opacify(0.5)
                drawer.fill = ColorRGBa.PINK.opacify(0.5)
                drawer.translate(420.0, 0.0)
                drawTestShapes(this)
            }
            drawer.isolated {
                drawer.stroke = ColorRGBa.fromHex(0x00ffff).opacify(0.5)
                drawer.fill = ColorRGBa.fromHex(0xff00ff)
                drawer.translate(0.0, 420.0)
                drawTestShapes(this)
            }
            drawer.isolated {
                drawer.stroke = ColorRGBa.fromHex(0x00ffff).opacify(0.5)
                drawer.fill = ColorRGBa.fromHex(0xff00ff).opacify(0.5)
                drawer.translate(420.0, 420.0)
                drawTestShapes(this)
            }
        }
    }
}

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
bug Something isn't working
Projects
None yet
Development

No branches or pull requests

1 participant