1- import { distance , rad , loopAccess } from "./util" ;
2- import { Point , renderClosed } from "./render" ;
1+ // https://www.blobmaker.app/
2+ // https://math.stackexchange.com/questions/873224/calculate-control-points-of-cubic-bezier-curve-approximating-a-part-of-a-circle
33
4- export interface BlobOptions {
5- size : number ;
6- color : string ;
7- complexity : number ;
8- contrast : number ;
9- }
4+ import { rad , smooth } from "./util" ;
5+ import { render } from "./render" ;
6+ import { Point , BlobOptions } from "./types" ;
7+
8+ export { BlobOptions } from "./types" ;
109
1110// Generates a random rounded shape.
1211export const blob = ( opt : BlobOptions ) : string => {
1312 opt = Object . assign ( { } , opt ) ;
1413
14+ if ( ! opt . stroke && ! opt . color ) {
15+ throw new Error ( "no color or stroke specified" )
16+ }
17+
1518 if ( opt . complexity <= 0 || opt . complexity > 1 ) {
1619 throw new Error ( "complexity out of range ]0,1]" ) ;
1720 }
@@ -22,8 +25,7 @@ export const blob = (opt: BlobOptions): string => {
2225
2326 const count = 3 + Math . floor ( 14 * opt . complexity ) ;
2427 const angle = 360 / count ;
25- const radius = opt . size / 3 ;
26- const handle = radius * ( 4 / 3 ) * Math . tan ( rad ( angle / 4 ) ) ;
28+ const radius = opt . size / Math . E ;
2729
2830 const points : Point [ ] = [ ] ;
2931 for ( let i = 0 ; i < count ; i ++ ) {
@@ -32,33 +34,23 @@ export const blob = (opt: BlobOptions): string => {
3234 points . push ( {
3335 x : Math . sin ( rad ( i * angle ) ) * radius * rand + opt . size / 2 ,
3436 y : Math . cos ( rad ( i * angle ) ) * radius * rand + opt . size / 2 ,
35- handles : {
36- angle : - i * angle ,
37- in : handle ,
38- out : handle ,
39- } ,
4037 } ) ;
4138 }
4239
43- // Adjust handle lengths according to proximity with adjacent points.
44- const expected = 2 * radius * Math . sin ( rad ( angle / 2 ) ) ;
45- for ( let i = 0 ; i < count ; i ++ ) {
46- const point = loopAccess ( points ) ( i ) ;
47- if ( ! point . handles ) continue ; // Should not happen.
48-
49- const { handles} = point ;
50- handles . in = ( handles . in * distance ( point , loopAccess ( points ) ( i - 1 ) ) ) / expected ;
51- handles . out = ( handles . out * distance ( point , loopAccess ( points ) ( i + 1 ) ) ) / expected ;
52- }
40+ const smoothed = smooth ( points , {
41+ closed : true ,
42+ strength : ( 4 / 3 ) * Math . tan ( rad ( angle / 4 ) ) / Math . sin ( rad ( angle / 2 ) ) ,
43+ } ) ;
5344
54- return renderClosed ( points , {
45+ return render ( smoothed , {
46+ closed : true ,
5547 width : opt . size ,
5648 height : opt . size ,
5749 fill : opt . color ,
5850 transform : `rotate(${ Math . random ( ) * angle } ,${ opt . size / 2 } ,${ opt . size / 2 } )` ,
59- stroke : "red" ,
60- strokeWidth : 2 ,
61- guides : true ,
51+ stroke : ( opt . stroke && opt . stroke . color ) ,
52+ strokeWidth : ( opt . stroke && opt . stroke . width ) ,
53+ guides : opt . guides ,
6254 } ) ;
6355} ;
6456
@@ -68,24 +60,10 @@ console.log(
6860 complexity : 0.2 ,
6961 contrast : 1 ,
7062 size : 600 ,
63+ guides : true ,
64+ stroke : {
65+ color : "red" ,
66+ width : 1.8 ,
67+ } ,
7168 } ) ,
7269) ;
73-
74- // console.log(
75- // renderClosed(
76- // [
77- // {x: 700, y: 200, handles: {angle: -135, out: 80, in: 80}},
78- // {x: 300, y: 200, handles: {angle: 135, out: 80, in: 80}},
79- // {x: 300, y: 600, handles: {angle: 45, out: 80, in: 80}},
80- // {x: 700, y: 600, handles: {angle: -45, out: 80, in: 80}},
81- // ],
82- // {
83- // width: 1000,
84- // height: 800,
85- // fill: "pink",
86- // stroke: "red",
87- // strokeWidth: 2,
88- // guides: true,
89- // },
90- // ),
91- // );
0 commit comments