Skip to content

Commit

Permalink
Add BlRoundedPolygonGeometry
Browse files Browse the repository at this point in the history
- tests needed
- containsPoint: is not precise
- we should cache some calculated values, to avoid repeating the same maths on every new frame
- this is the closed polygon, it's a pity we don't support being an open geometry (a "polyline")
- we may decide to do some refactorings such as merge it with it's superclass
  • Loading branch information
tinchodias committed Apr 8, 2024
1 parent badeace commit 5ed4ec6
Show file tree
Hide file tree
Showing 2 changed files with 111 additions and 0 deletions.
79 changes: 79 additions & 0 deletions src/Bloc-Alexandrie/BlRoundedPolygonGeometry.extension.st
Original file line number Diff line number Diff line change
@@ -0,0 +1,79 @@
Extension { #name : #BlRoundedPolygonGeometry }

{ #category : #'*Bloc-Alexandrie' }
BlRoundedPolygonGeometry >> aeApplyTo: aeCanvas element: aBlElement [

aeCanvas pathFactory: [ :cairoContext |
| p1 p2 p3 |
1 to: vertices size do: [ :i |
p1 := vertices at: i.
p2 := vertices atWrap: i + 1.
p3 := vertices atWrap: i + 2.
self
aeApplyTo: cairoContext
roundedCornerP1: p1
p2: p2
p3: p3 ].

cairoContext closePath ]
]

{ #category : #'*Bloc-Alexandrie' }
BlRoundedPolygonGeometry >> aeApplyTo: cairoContext roundedCornerP1: p1 p2: p2 p3: p3 [
"Based on `RSAthensRenderer>>#applyRadius:on:from:to:`, which is based on
https://riptutorial.com/html5-canvas/example/18766/render-a-rounded-polygon-"

| v1 len1 a1 v2 len2 a2 sinA sin90 angle radDir isClockwise halfAngle cRadius lenOut p a b |
(p1 = p2 or: [ p2 = p3 ]) ifTrue: [ ^ self ].

v1 := p1 - p2.
len1 := ((v1 x * v1 x) + (v1 y * v1 y)) sqrt.
v1 := v1 / len1.
a1 := v1 angle.

v2 := p3 - p2.
len2 := ((v2 x * v2 x) + (v2 y * v2 y)) sqrt.
v2 := v2 / len2.
a2 := v2 angle.

sinA := (v1 x * v2 y) - (v1 y * v2 x).
sin90 := (v1 x * v2 x) - (v1 y * v2 y negated).
angle := sinA arcSin.
radDir := 1.
isClockwise := true.

sin90 < 0.0
ifTrue: [
angle < 0.0
ifTrue: [ angle := angle + Float pi ]
ifFalse: [
angle := angle - Float pi.
radDir := -1.
isClockwise := false ] ]
ifFalse: [
angle >= 0.0 ifTrue: [
radDir := -1.
isClockwise := false ] ].

halfAngle := angle / 2.0.
sinA := halfAngle sin.
lenOut := (sinA closeTo: 0.0)
ifTrue: [ Float infinity ]
ifFalse: [ (halfAngle cos * radius / sinA) abs ].
cRadius := radius.
lenOut > ((len1 / 2.0) min: (len2 / 2.0)) ifTrue: [
lenOut := (len1 / 2.0) min: (len2 / 2.0).
cRadius := (lenOut * halfAngle tan) abs ].

p := p2 + (v2 * lenOut) + (v2 y negated@ v2 x * cRadius * radDir).
a := a1 + (Float halfPi * radDir).
b := a2 - (Float halfPi * radDir).
(a closeTo: b) ifTrue: [ a := b ].

cairoContext
arcCenter: p
radius: cRadius
startAngle: a
endAngle: b
cw: isClockwise
]
32 changes: 32 additions & 0 deletions src/Bloc/BlRoundedPolygonGeometry.class.st
Original file line number Diff line number Diff line change
@@ -0,0 +1,32 @@
"
I represent a polygon with rounded corners. The arc is indicated by the radius (same radius for all corners).
"
Class {
#name : #BlRoundedPolygonGeometry,
#superclass : #BlPolygonGeometry,
#instVars : [
'radius'
],
#category : #'Bloc-Basic-Geometry'
}

{ #category : #'instance creation' }
BlRoundedPolygonGeometry class >> vertices: aCollection radius: aNumber [

^ self new
vertices: aCollection;
radius: aNumber;
yourself
]

{ #category : #accessing }
BlRoundedPolygonGeometry >> radius [

^ radius
]

{ #category : #accessing }
BlRoundedPolygonGeometry >> radius: anInteger [

radius := anInteger
]

0 comments on commit 5ed4ec6

Please sign in to comment.