Skip to content

Commit cc8ae0e

Browse files
committed
New RoundedRect class
1 parent 2ea49c9 commit cc8ae0e

File tree

3 files changed

+56
-5
lines changed

3 files changed

+56
-5
lines changed

src/draw-svg.ts

Lines changed: 16 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -11,7 +11,7 @@ import {intersections} from './intersection';
1111
import {Line} from './line';
1212
import {Point} from './point';
1313
import {Rectangle} from './rectangle';
14-
import {isAngle, isArc, isCircle, isEllipse, isLine, isPolygon, isPolyline, isRay, isRectangle, isSector, isSegment} from './types';
14+
import {isAngle, isArc, isCircle, isEllipse, isLine, isPolygon, isPolyline, isRay, isRectangle, isRoundedRect, isSector, isSegment} from './types';
1515
import {GeoElement} from './utilities';
1616

1717

@@ -105,6 +105,15 @@ function drawArcArrows(x: Arc, type: LineArrow) {
105105
return path;
106106
}
107107

108+
const p1 = 0.55192;
109+
const p2 = 1 - p1;
110+
export function drawRoundedRect(rect: Rectangle, radius: number[]) {
111+
const [tl, tr, br, bl] = radius; // top-left, top-right, btm-right, btm-left
112+
const {p, w, h} = rect;
113+
const wx = w - tl - tr;
114+
return `M${p.x} ${p.y + tl}c0 ${-p1 * tl} ${p2 * tl} ${-tl} ${tl} ${-tl}h${wx}c${p1 * tr} 0 ${tr} ${p2 * tr} ${tr} ${tr}v${h - tr - br}c0 ${p1 * br} ${-p2 * br} ${br} ${-br} ${br}h${-wx}c${-p1 * bl} 0 ${-bl} ${-p2 * bl} ${-bl} ${-bl}Z`;
115+
}
116+
108117

109118
// -----------------------------------------------------------------------------
110119
// Draw Function
@@ -171,6 +180,12 @@ export function drawSVG(obj: GeoElement, options: SVGDrawingOptions = {}): strin
171180
return `${drawPath(...obj.points)}Z`;
172181
}
173182

183+
if (isRoundedRect(obj)) {
184+
const rect = obj.unsigned;
185+
const r = Math.min(obj.radius, rect.w / 2, rect.h / 2);
186+
return drawRoundedRect(rect, [r, r, r, r]);
187+
}
188+
174189
if (isRectangle(obj)) {
175190
return `${drawPath(...obj.polygon.points)}Z`;
176191
}

src/rectangle.ts

Lines changed: 34 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -14,7 +14,7 @@ import {GeoShape, SimplePoint, TransformMatrix} from './utilities';
1414

1515
/** A rectangle, defined by its top left vertex, width and height. */
1616
export class Rectangle implements GeoShape {
17-
readonly type = 'rectangle';
17+
readonly type: string = 'rectangle';
1818

1919
constructor(readonly p: Point, readonly w = 1, readonly h = w) {}
2020

@@ -48,7 +48,11 @@ export class Rectangle implements GeoShape {
4848
}
4949

5050
get area() {
51-
return Math.abs(this.w * this.h);
51+
return Math.abs(this.signedArea);
52+
}
53+
54+
get signedArea() {
55+
return this.w * this.h;
5256
}
5357

5458
/** @returns {Segment[]} */
@@ -82,6 +86,16 @@ export class Rectangle implements GeoShape {
8286
return new Rectangle(this.p.shift(-left, -top), this.w + left + right, this.h + top + bottom);
8387
}
8488

89+
round(radius: number) {
90+
return new RoundedRect(this.p, this.w, this.h, radius);
91+
}
92+
93+
get unsigned(): Rectangle {
94+
if (this.w > 0 && this.h > 0) return this;
95+
const p = this.p.shift(this.w < 0 ? this.w : 0, this.h < 0 ? this.h : 0);
96+
return new Rectangle(p, Math.abs(this.w), Math.abs(this.h));
97+
}
98+
8599
// ---------------------------------------------------------------------------
86100

87101
contains(p: Point, tolerance?: number) {
@@ -145,3 +159,21 @@ export class Rectangle implements GeoShape {
145159
return `rectangle(${this.p},${this.w},${this.h})`;
146160
}
147161
}
162+
163+
/** A triangle defined by its three vertices. */
164+
export class RoundedRect extends Rectangle {
165+
readonly type = 'rounded-rect';
166+
167+
constructor(p: Point, w = 1, h = w, readonly radius = 0) {
168+
super(p, w, h);
169+
}
170+
171+
scale(sx: number, sy = sx) {
172+
const r1 = this.radius * (sx + sy) / 2;
173+
return super.scale(sx, sy).round(r1);
174+
}
175+
176+
shift(x: number, y = x) {
177+
return super.shift(x, y).round(this.radius);
178+
}
179+
}

src/types.ts

Lines changed: 6 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -11,12 +11,12 @@ import {Ellipse} from './ellipse';
1111
import {Line, Ray, Segment} from './line';
1212
import {Point} from './point';
1313
import {Polygon, Polyline} from './polygon';
14-
import {Rectangle} from './rectangle';
14+
import {Rectangle, RoundedRect} from './rectangle';
1515
import {GeoElement} from './utilities';
1616

1717

1818
export function isPolygonLike(shape: GeoElement): shape is Polygon|Rectangle {
19-
return ['polygon', 'polyline', 'rectangle', 'triangle'].includes(shape.type);
19+
return ['polygon', 'polyline', 'rectangle', 'rounded-rect', 'triangle'].includes(shape.type);
2020
}
2121

2222
export function isPolygon(shape: GeoElement): shape is Polygon {
@@ -31,6 +31,10 @@ export function isRectangle(shape: GeoElement): shape is Rectangle {
3131
return shape.type === 'rectangle';
3232
}
3333

34+
export function isRoundedRect(shape: GeoElement): shape is RoundedRect {
35+
return shape.type === 'rounded-rect';
36+
}
37+
3438
export function isLineLike(shape: GeoElement): shape is Line|Ray|Segment {
3539
return ['line', 'ray', 'segment'].includes(shape.type);
3640
}

0 commit comments

Comments
 (0)