androidandroid-jetpack-compose

How to draw an outlined reuleaux triangle in Jetpack Compose Canvas?


I'm trying to create an outlined reuleaux triangle using Jetpack Compose.

I try this code:

@Composable
fun ReuleauxTriangle() {
    Canvas(
            modifier = Modifier
                .fillMaxWidth()
                .aspectRatio(1f)
                
        ) {
            val rect = Rect(Offset.Zero, size)
            val trianglePath = Path().apply {
                moveTo(rect.topCenter)
                lineTo(rect.bottomRight)
                lineTo(rect.bottomLeft)
                close()
            }

            drawIntoCanvas { canvas ->
                canvas.drawOutline(
                    outline = Outline.Generic(trianglePath),
                    paint = Paint().apply {
                        color = Color.Black
                        pathEffect = PathEffect.cornerPathEffect(rect.maxDimension / 3)
                    }
                )
            }
        }
    
}

Path helpers:

fun Path.moveTo(offset: Offset) = moveTo(offset.x, offset.y)
fun Path.lineTo(offset: Offset) = lineTo(offset.x, offset.y)

Result | Expected

How can I draw the expected below ?


Solution

  • I'm using quadratic bezier curve to draw one segment, then i rotate it 2 more times by 120 degrees to create the full triangle.

    Here is the code:

    @Composable
    fun ReuleauxTriangle(modifier: Modifier = Modifier) {
        Canvas(
            modifier = modifier
                .fillMaxSize()
                .aspectRatio(1f)
        ) {
            val diameter = size.minDimension
    
            val delta = 0.21f*diameter
    
            val topCenter = Offset(diameter / 2, 0f)
            val bottomLeft = Offset(0f, diameter-delta)
            val bottomRight = Offset(diameter, diameter-delta)
    
            val control = Offset(topCenter.x, diameter)
    
            val segmentPath = Path().apply {
                moveTo(bottomLeft.x, bottomLeft.y)
                quadraticTo(control.x, control.y, bottomRight.x, bottomRight.y)
            }
    
            repeat(3) {
                rotate(it * 120f) {
                    drawPath(
                        path = segmentPath,
                        color = Color.Black,
                        style = Stroke(width = 4f)
                    )
                }
            }
        }
    }
    

    Usage:

    ReuleauxTriangle(
        modifier = Modifier
            .size(200.dp)
    )
    

    Demo:

    enter image description here