@@ -466,6 +466,77 @@ class Quad extends ShapePrimitive {
466466 }
467467}
468468
469+ class ArcPrimitive extends ShapePrimitive {
470+ #x;
471+ #y;
472+ #w;
473+ #h;
474+ #start;
475+ #stop;
476+ #mode;
477+ // vertexCapacity 0 means this primitive should not accumulate normal path vertices
478+ #vertexCapacity = 0 ;
479+
480+ constructor ( x , y , w , h , start , stop , mode ) {
481+ // ShapePrimitive requires at least one vertex; pass a placeholder
482+ super ( new Vertex ( { position : new Vector ( x + w / 2 , y + h / 2 ) } ) ) ;
483+ this . #x = x ;
484+ this . #y = y ;
485+ this . #w = w ;
486+ this . #h = h ;
487+ this . #start = start ;
488+ this . #stop = stop ;
489+ this . #mode = mode ;
490+ }
491+
492+ get x ( ) { return this . #x; }
493+ get y ( ) { return this . #y; }
494+ get w ( ) { return this . #w; }
495+ get h ( ) { return this . #h; }
496+ get start ( ) { return this . #start; }
497+ get stop ( ) { return this . #stop; }
498+ get mode ( ) { return this . #mode; }
499+
500+ get vertexCapacity ( ) {
501+ return this . #vertexCapacity;
502+ }
503+
504+ accept ( visitor ) {
505+ visitor . visitArcPrimitive ( this ) ;
506+ }
507+ }
508+
509+ class EllipsePrimitive extends ShapePrimitive {
510+ #x;
511+ #y;
512+ #w;
513+ #h;
514+ // vertexCapacity 0 means this primitive should not accumulate normal path vertices
515+ #vertexCapacity = 0 ;
516+
517+ constructor ( x , y , w , h ) {
518+
519+ super ( new Vertex ( { position : new Vector ( x + w / 2 , y + h / 2 ) } ) ) ;
520+ this . #x = x ;
521+ this . #y = y ;
522+ this . #w = w ;
523+ this . #h = h ;
524+ }
525+
526+ get x ( ) { return this . #x; }
527+ get y ( ) { return this . #y; }
528+ get w ( ) { return this . #w; }
529+ get h ( ) { return this . #h; }
530+
531+ get vertexCapacity ( ) {
532+ return this . #vertexCapacity;
533+ }
534+
535+ accept ( visitor ) {
536+ visitor . visitEllipsePrimitive ( this ) ;
537+ }
538+ }
539+
469540// ---- TESSELLATION PRIMITIVES ----
470541
471542class TriangleFan extends ShapePrimitive {
@@ -1003,6 +1074,12 @@ class PrimitiveVisitor {
10031074 visitArcSegment ( arcSegment ) {
10041075 throw new Error ( 'Method visitArcSegment() has not been implemented.' ) ;
10051076 }
1077+ visitArcPrimitive ( arc ) {
1078+ throw new Error ( 'Method visitArcPrimitive() has not been implemented.' ) ;
1079+ }
1080+ visitEllipsePrimitive ( ellipse ) {
1081+ throw new Error ( 'Method visitEllipsePrimitive() has not been implemented.' ) ;
1082+ }
10061083
10071084 // isolated primitives
10081085 visitPoint ( point ) {
@@ -1151,6 +1228,34 @@ class PrimitiveToPath2DConverter extends PrimitiveVisitor {
11511228 this . path . closePath ( ) ;
11521229 }
11531230 }
1231+ visitArcPrimitive ( arc ) {
1232+ const centerX = arc . x + arc . w / 2 ;
1233+ const centerY = arc . y + arc . h / 2 ;
1234+ const radiusX = arc . w / 2 ;
1235+ const radiusY = arc . h / 2 ;
1236+
1237+ this . path . ellipse (
1238+ centerX , centerY , radiusX , radiusY , 0 , arc . start , arc . stop
1239+ ) ;
1240+
1241+ if ( arc . mode === constants . OPEN ) {
1242+ // OPEN: leave path open — arc stroke/fill is just the curve
1243+ } else if ( arc . mode === constants . CHORD ) {
1244+
1245+ this . path . closePath ( ) ;
1246+ } else {
1247+ this . path . lineTo ( centerX , centerY ) ;
1248+ this . path . closePath ( ) ;
1249+ }
1250+ }
1251+ visitEllipsePrimitive ( ellipse ) {
1252+ const centerX = ellipse . x + ellipse . w / 2 ;
1253+ const centerY = ellipse . y + ellipse . h / 2 ;
1254+ const radiusX = ellipse . w / 2 ;
1255+ const radiusY = ellipse . h / 2 ;
1256+
1257+ this . path . ellipse ( centerX , centerY , radiusX , radiusY , 0 , 0 , 2 * Math . PI ) ;
1258+ }
11541259 visitQuadStrip ( quadStrip ) {
11551260 for ( let i = 0 ; i < quadStrip . vertices . length - 3 ; i += 2 ) {
11561261 const v0 = quadStrip . vertices [ i ] ;
@@ -1277,6 +1382,50 @@ class PrimitiveToVerticesConverter extends PrimitiveVisitor {
12771382 // WebGL itself interprets the vertices as a strip, no reformatting needed
12781383 this . contours . push ( quadStrip . vertices . slice ( ) ) ;
12791384 }
1385+ visitArcPrimitive ( arc ) {
1386+ const centerX = arc . x + arc . w / 2 ;
1387+ const centerY = arc . y + arc . h / 2 ;
1388+ const radiusX = arc . w / 2 ;
1389+ const radiusY = arc . h / 2 ;
1390+ const numPoints = Math . max ( 3 , this . curveDetail ) ;
1391+ const verts = [ ] ;
1392+
1393+ if ( arc . mode === constants . PIE ) {
1394+ verts . push ( new Vertex ( { position : new Vector ( centerX , centerY ) } ) ) ;
1395+ }
1396+
1397+ for ( let i = 0 ; i <= numPoints ; i ++ ) {
1398+ const angle = arc . start + ( arc . stop - arc . start ) * ( i / numPoints ) ;
1399+ verts . push ( new Vertex ( {
1400+ position : new Vector (
1401+ centerX + radiusX * Math . cos ( angle ) ,
1402+ centerY + radiusY * Math . sin ( angle )
1403+ )
1404+ } ) ) ;
1405+ }
1406+
1407+ this . contours . push ( verts ) ;
1408+ }
1409+ visitEllipsePrimitive ( ellipse ) {
1410+ const centerX = ellipse . x + ellipse . w / 2 ;
1411+ const centerY = ellipse . y + ellipse . h / 2 ;
1412+ const radiusX = ellipse . w / 2 ;
1413+ const radiusY = ellipse . h / 2 ;
1414+ const numPoints = Math . max ( 3 , this . curveDetail ) ;
1415+ const verts = [ ] ;
1416+
1417+ for ( let i = 0 ; i <= numPoints ; i ++ ) {
1418+ const angle = ( 2 * Math . PI * i ) / numPoints ;
1419+ verts . push ( new Vertex ( {
1420+ position : new Vector (
1421+ centerX + radiusX * Math . cos ( angle ) ,
1422+ centerY + radiusY * Math . sin ( angle )
1423+ )
1424+ } ) ) ;
1425+ }
1426+
1427+ this . contours . push ( verts ) ;
1428+ }
12801429}
12811430
12821431class PointAtLengthGetter extends PrimitiveVisitor {
@@ -2793,6 +2942,8 @@ export {
27932942 Line ,
27942943 Triangle ,
27952944 Quad ,
2945+ ArcPrimitive ,
2946+ EllipsePrimitive ,
27962947 TriangleFan ,
27972948 TriangleStrip ,
27982949 QuadStrip ,
0 commit comments