CIMSymbolDrawHelper.js 22 KB

12345
  1. /*
  2. All material copyright ESRI, All Rights Reserved, unless otherwise specified.
  3. See https://js.arcgis.com/4.25/esri/copyright.txt for details.
  4. */
  5. import{bidiText as t}from"../../core/BidiText.js";import{getFontFamily as e}from"../../core/fontUtils.js";import{clone as r}from"../../core/lang.js";import i from"../../core/Logger.js";import{isNone as s,isSome as o}from"../../core/maybe.js";import n from"../../core/ObjectPool.js";import{px2pt as a,pt2px as l}from"../../core/screenUtils.js";import{create as h,fromValues as c}from"../../geometry/support/aaBoundingRect.js";import{getBoundsXY as m}from"../../geometry/support/boundsUtils.js";import{polygonCentroid as f}from"../../geometry/support/centroid.js";import{isPoint as u,isPolygon as p,isPolyline as d,isExtent as _,isMultipoint as g}from"../../geometry/support/jsonUtils.js";import{SimpleGeometryCursor as y}from"./CIMEffects.js";import P from"./CIMImageColorSubstitutionHelper.js";import{getEffectOperator as w,getPlacementOperator as x}from"./CIMOperators.js";import{Placement as S}from"./CIMPlacements.js";import{LineCapStyle as M,LineJoinStyle as b}from"./enums.js";import{getFirstFrame as k}from"./imageUtils.js";import C from"./Rect.js";import T from"./TextRasterizer.js";import{isSVGImage as I,fromCIMFontDecoration as R,fromCIMFontStyle as v,fromCIMHorizontalAlignment as z,fromCIMVerticalAlignment as F,getFillColor as L,getStrokeColor as A,getFontStyle as j,getFontWeight as U}from"./utils.js";import{HAlign as H,VAlign as B}from"../../views/2d/engine/webgl/alignmentUtils.js";import{GLYPH_SIZE as D,MAGIC_LABEL_LINE_HEIGHT as G}from"../../views/2d/engine/webgl/definitions.js";import{shapeGlyphs as X}from"../../views/2d/engine/webgl/mesh/templates/shapingUtils.js";const E=Math.PI/180,J=10,N=i.getLogger("esri.symbols.cim.CIMSymbolDrawHelper");class O{constructor(t){this._t=t}static createIdentity(){return new O([1,0,0,0,1,0])}clone(){const t=this._t;return new O(t.slice())}transform(t){const e=this._t;return[e[0]*t[0]+e[1]*t[1]+e[2],e[3]*t[0]+e[4]*t[1]+e[5]]}static createScale(t,e){return new O([t,0,0,0,e,0])}scale(t,e){const r=this._t;return r[0]*=t,r[1]*=t,r[2]*=t,r[3]*=e,r[4]*=e,r[5]*=e,this}scaleRatio(){return Math.sqrt(this._t[0]*this._t[0]+this._t[1]*this._t[1])}static createTranslate(t,e){return new O([0,0,t,0,0,e])}translate(t,e){const r=this._t;return r[2]+=t,r[5]+=e,this}static createRotate(t){const e=Math.cos(t),r=Math.sin(t);return new O([e,-r,0,r,e,0])}rotate(t){return O.multiply(this,O.createRotate(t),this)}angle(){const t=this._t[0],e=this._t[3],r=Math.sqrt(t*t+e*e);return[t/r,e/r]}static multiply(t,e,r){const i=t._t,s=e._t,o=i[0]*s[0]+i[3]*s[1],n=i[1]*s[0]+i[4]*s[1],a=i[2]*s[0]+i[5]*s[1]+s[2],l=i[0]*s[3]+i[3]*s[4],h=i[1]*s[3]+i[4]*s[4],c=i[2]*s[3]+i[5]*s[4]+s[5],m=r._t;return m[0]=o,m[1]=n,m[2]=a,m[3]=l,m[4]=h,m[5]=c,r}invert(){const t=this._t;let e=t[0]*t[4]-t[1]*t[3];if(0===e)return new O([0,0,0,0,0,0]);e=1/e;const r=(t[1]*t[5]-t[2]*t[4])*e,i=(t[2]*t[3]-t[0]*t[5])*e,s=t[4]*e,o=-t[1]*e,n=-t[3]*e,a=t[0]*e;return new O([s,o,r,n,a,i])}}class Y{constructor(t,e){this._resourceManager=t,this._transfos=[],this._sizeTransfos=[],this._geomUnitsPerPoint=1,this._placementPool=new n(S,void 0,void 0,100),this._earlyReturn=!1,this._mapRotation=0,this._transfos.push(e||O.createIdentity()),this._sizeTransfos.push(e?e.scaleRatio():1)}setTransform(t,e){this._transfos=[t||O.createIdentity()],this._sizeTransfos=[e||(t?t.scaleRatio():1)]}setGeomUnitsPerPoint(t){this._geomUnitsPerPoint=t}transformPt(t){return this._transfos[this._transfos.length-1].transform(t)}transformSize(t){return t*this._sizeTransfos[this._sizeTransfos.length-1]}reverseTransformPt(t){return this._transfos[this._transfos.length-1].invert().transform(t)}reverseTransformSize(t){return t/this._sizeTransfos[this._sizeTransfos.length-1]}getTransformAngle(){return this._transfos[this._transfos.length-1].angle()}geomUnitsPerPoint(){return this.isEmbedded()?1:this._geomUnitsPerPoint}isEmbedded(){return this._transfos.length>1}back(){return this._transfos[this._transfos.length-1]}push(t,e){const r=e?t.scaleRatio():1;O.multiply(t,this.back(),t),this._transfos.push(t),this._sizeTransfos.push(this._sizeTransfos[this._sizeTransfos.length-1]*r)}pop(){this._transfos.splice(-1,1),this._sizeTransfos.splice(-1,1)}drawSymbol(t,e,r){if(t)switch(t.type){case"CIMPointSymbol":case"CIMLineSymbol":case"CIMPolygonSymbol":this.drawMultiLayerSymbol(t,e);break;case"CIMTextSymbol":this.drawTextSymbol(t,e,r)}}drawMultiLayerSymbol(t,e){if(!t)return;const r=t.symbolLayers;if(!r)return;const i=t.effects;if(i&&i.length>0){const t=this.executeEffects(i,e);if(t){let e=t.next();for(;e;)this.drawSymbolLayers(r,e),e=t.next()}}else this.drawSymbolLayers(r,e)}executeEffects(t,e){const r=this._resourceManager.geometryEngine;let i=new y(e);for(const s of t){const t=w(s);t&&(i=t.execute(i,s,this.geomUnitsPerPoint(),r))}return i}drawSymbolLayers(t,e){let r=t.length;for(;r--;){const i=t[r];if(!i||!1===i.enable)continue;const s=i.effects;if(s&&s.length>0){const t=this.executeEffects(s,e);if(t){let e=null;for(;(e=t.next())&&(this.drawSymbolLayer(i,e),!this._earlyReturn););}}else this.drawSymbolLayer(i,e);if(this._earlyReturn)return}}drawSymbolLayer(t,e){switch(t.type){case"CIMSolidFill":this.drawSolidFill(e,t.color);break;case"CIMHatchFill":this.drawHatchFill(e,t);break;case"CIMPictureFill":this.drawPictureFill(e,t);break;case"CIMGradientFill":this.drawGradientFill(e,t);break;case"CIMSolidStroke":this.drawSolidStroke(e,t.color,t.width,t.capStyle,t.joinStyle,t.miterLimit);break;case"CIMPictureStroke":this.drawPictureStroke(e,t);break;case"CIMGradientStroke":this.drawGradientStroke(e,t);break;case"CIMCharacterMarker":case"CIMPictureMarker":case"CIMVectorMarker":this.drawMarkerLayer(t,e)}}drawHatchFill(t,e){const r=this._buildHatchPolyline(e,t,this.geomUnitsPerPoint());r&&(this.pushClipPath(t),this.drawMultiLayerSymbol(e.lineSymbol,r),this.popClipPath())}drawPictureFill(t,e){}drawGradientFill(t,e){}drawPictureStroke(t,e){}drawGradientStroke(t,e){}drawMarkerLayer(t,e){const r=t.markerPlacement;if(r){const i=x(r);if(i){const s="CIMMarkerPlacementInsidePolygon"===r.type||"CIMMarkerPlacementPolygonCenter"===r.type&&r.clipAtBoundary;s&&this.pushClipPath(e);const o=i.execute(e,r,this.geomUnitsPerPoint(),this._resourceManager.geometryEngine);if(o){let e=null;for(;(e=o.next())&&(this.drawMarker(t,e),!this._earlyReturn););}s&&this.popClipPath()}}else{const r=this._placementPool.acquire();if(u(e))r.tx=e.x,r.ty=e.y,this.drawMarker(t,r);else if(p(e))[r.tx,r.ty]=f(e),this.drawMarker(t,r);else for(const i of e.points)if(r.tx=i[0],r.ty=i[1],this.drawMarker(t,r),this._earlyReturn)break;this._placementPool.release(r)}}drawMarker(t,e){switch(t.type){case"CIMCharacterMarker":case"CIMPictureMarker":this.drawPictureMarker(t,e);break;case"CIMVectorMarker":this.drawVectorMarker(t,e)}}drawPictureMarker(t,e){if(!t)return;const r=this._resourceManager.getResource(t.url),i=t.size??10;if(s(r)||i<=0)return;const o=r.width,n=r.height;if(!o||!n)return;const a=o/n,l=t.scaleX??1,h=O.createIdentity(),c=t.anchorPoint;if(c){let e=c.x,r=c.y;"Absolute"!==t.anchorPointUnits&&(e*=i*a*l,r*=i),h.translate(-e,-r)}let m=t.rotation??0;t.rotateClockwise&&(m=-m),this._mapRotation&&(m+=this._mapRotation),m&&h.rotate(m*E);let f=t.offsetX??0,u=t.offsetY??0;if(f||u){if(this._mapRotation){const t=E*this._mapRotation,e=Math.cos(t),r=Math.sin(t),i=f*r+u*e;f=f*e-u*r,u=i}h.translate(f,u)}const p=this.geomUnitsPerPoint();1!==p&&h.scale(p,p);const d=e.getAngle();d&&h.rotate(d),h.translate(e.tx,e.ty),this.push(h,!1),this.drawImage(t,i),this.pop()}drawVectorMarker(t,e){if(!t)return;const r=t.markerGraphics;if(!r)return;const i=t.size??10,s=t.frame,o=s?s.ymax-s.ymin:0,n=i&&o?i/o:1,a=O.createIdentity();s&&a.translate(.5*-(s.xmax+s.xmin),.5*-(s.ymax+s.ymin));const l=t.anchorPoint;if(l){let e=l.x,r=l.y;"Absolute"!==t.anchorPointUnits?s&&(e*=s.xmax-s.xmin,r*=s.ymax-s.ymin):(e/=n,r/=n),a.translate(-e,-r)}1!==n&&a.scale(n,n);let h=t.rotation??0;t.rotateClockwise&&(h=-h),this._mapRotation&&(h+=this._mapRotation),h&&a.rotate(h*E);let c=t.offsetX??0,m=t.offsetY??0;if(c||m){if(this._mapRotation){const t=E*this._mapRotation,e=Math.cos(t),r=Math.sin(t),i=c*r+m*e;c=c*e-m*r,m=i}a.translate(c,m)}const f=this.geomUnitsPerPoint();1!==f&&a.scale(f,f);const u=e.getAngle();u&&a.rotate(u),a.translate(e.tx,e.ty),this.push(a,t.scaleSymbolsProportionally);for(const p of r)if(p&&p.symbol&&p.geometry||N.error("Invalid marker graphic",p),this.drawSymbol(p.symbol,p.geometry,p.textString),this._earlyReturn)break;this.pop()}drawTextSymbol(t,e,r){if(!t)return;if(!u(e))return;if((t.height??10)<=0)return;const i=O.createIdentity();let s=t.angle??0;s=-s,s&&i.rotate(s*E);const o=t.offsetX??0,n=t.offsetY??0;(o||n)&&i.translate(o,n);const a=this.geomUnitsPerPoint();1!==a&&i.scale(a,a),i.translate(e.x,e.y),this.push(i,!1),this.drawText(t,r),this.pop()}_buildHatchPolyline(t,e,r){let i=(void 0!==t.separation?t.separation:4)*r,s=void 0!==t.rotation?t.rotation:0;if(0===i)return null;i<0&&(i=-i);let o=0;const n=.5*i;for(;o>n;)o-=i;for(;o<-n;)o+=i;const a=h();m(a,e),a[0]-=n,a[1]-=n,a[2]+=n,a[3]+=n;const l=[[a[0],a[1]],[a[0],a[3]],[a[2],a[3]],[a[2],a[1]]];for(;s>180;)s-=180;for(;s<0;)s+=180;const c=Math.cos(s*E),f=Math.sin(s*E),u=-i*f,p=i*c;let d,_,g,y;o=(void 0!==t.offsetX?t.offsetX*r:0)*f-(void 0!==t.offsetY?t.offsetY*r:0)*c,d=g=Number.MAX_VALUE,_=y=-Number.MAX_VALUE;for(const h of l){const t=h[0],e=h[1],r=c*t+f*e,i=-f*t+c*e;d=Math.min(d,r),g=Math.min(g,i),_=Math.max(_,r),y=Math.max(y,i)}g=Math.floor(g/i)*i;let P=c*d-f*g-u*o/i,w=f*d+c*g-p*o/i,x=c*_-f*g-u*o/i,S=f*_+c*g-p*o/i;const M=1+Math.round((y-g)/i),b=[];for(let h=0;h<M;h++)P+=u,w+=p,x+=u,S+=p,b.push([[P,w],[x,S]]);return{paths:b}}}class q extends Y{constructor(t,e){super(t,e),this.reset()}reset(){this._xmin=this._ymin=1/0,this._xmax=this._ymax=-1/0,this._clipCount=0}envelope(){return new C(this._xmin,this._ymin,this._xmax-this._xmin,this._ymax-this._ymin)}bounds(){return c(this._xmin,this._ymin,this._xmax,this._ymax)}drawSolidFill(t){if(t&&!(this._clipCount>0))if(p(t))this._processPath(t.rings,0);else if(d(t))this._processPath(t.paths,0);else if(_(t)){const e=Q(t);e&&this._processPath(e.rings,0)}else console.error("drawSolidFill Unexpected geometry type!")}drawSolidStroke(t,e,r){if(!t||this._clipCount>0)return;const i=.5*this.transformSize(r);if(p(t))this._processPath(t.rings,i);else if(d(t))this._processPath(t.paths,i);else if(_(t)){const e=Q(t);e&&this._processPath(e.rings,i)}else console.error("drawSolidStroke unexpected geometry type!")}drawMarkerLayer(t,e){p(e)&&t.markerPlacement&&("CIMMarkerPlacementInsidePolygon"===t.markerPlacement.type||"CIMMarkerPlacementPolygonCenter"===t.markerPlacement.type&&t.markerPlacement.clipAtBoundary)?this._processPath(e.rings,0):super.drawMarkerLayer(t,e)}drawHatchFill(t,e){this.drawSolidFill(t)}drawPictureFill(t,e){this.drawSolidFill(t)}drawGradientFill(t,e){this.drawSolidFill(t)}drawPictureStroke(t,e){this.drawSolidStroke(t,null,e.width)}drawGradientStroke(t,e){this.drawSolidStroke(t,null,e.width)}pushClipPath(t){this.drawSolidFill(t),this._clipCount++}popClipPath(){this._clipCount--}drawImage(t,e){const{url:r}=t,i=t.scaleX??1;let s=i*e,n=e;const a=this._resourceManager.getResource(r);!e&&o(a)&&(s=i*a.width,n=a.height),this._merge(this.transformPt([-s/2,-n/2]),0),this._merge(this.transformPt([-s/2,n/2]),0),this._merge(this.transformPt([s/2,-n/2]),0),this._merge(this.transformPt([s/2,n/2]),0)}drawText(t,e){if(!e||0===e.length)return;this._textRasterizer||(this._textRasterizer=new T);const r=et(t),[i,s]=this._textRasterizer.computeTextSize(e,r);let o=0;switch(t.horizontalAlignment){case"Left":o=i/2;break;case"Right":o=-i/2}let n=0;switch(t.verticalAlignment){case"Bottom":n=s/2;break;case"Top":n=-s/2;break;case"Baseline":n=s/6}this._merge(this.transformPt([-i/2+o,-s/2+n]),0),this._merge(this.transformPt([-i/2+o,s/2+n]),0),this._merge(this.transformPt([i/2+o,-s/2+n]),0),this._merge(this.transformPt([i/2+o,s/2+n]),0)}_processPath(t,e){if(t)for(const r of t){const t=r?r.length:0;if(t>1){this._merge(this.transformPt(r[0]),e);for(let i=1;i<t;i++)this._merge(this.transformPt(r[i]),e)}}}_merge(t,e){t[0]-e<this._xmin&&(this._xmin=t[0]-e),t[0]+e>this._xmax&&(this._xmax=t[0]+e),t[1]-e<this._ymin&&(this._ymin=t[1]-e),t[1]+e>this._ymax&&(this._ymax=t[1]+e)}}class V extends Y{constructor(){super(...arguments),this._searchPoint=[0,0],this._searchDistPoint=0}hitTest(t,e,r,i,s,o){const n=o*l(1);this.setTransform(),this.setGeomUnitsPerPoint(n),this._searchPoint=[(t[0]+t[2])/2,(t[1]+t[3])/2],this._searchDistPoint=(t[2]-t[0])/2/n,this._textInfo=i;const a=e&&("CIMPointSymbol"===e.type&&"Map"!==e.angleAlignment||"CIMTextSymbol"===e.type);return this._mapRotation=a?s:0,this._earlyReturn=!1,this.drawSymbol(e,r),this._earlyReturn}drawSolidFill(t,e){this._hitTestFill(t)}drawHatchFill(t,e){this._hitTestFill(t)}drawPictureFill(t,e){this._hitTestFill(t)}drawGradientFill(t,e){this._hitTestFill(t)}drawSolidStroke(t,e,r,i,s,o){this._hitTestStroke(t,r)}drawPictureStroke(t,e){this._hitTestStroke(t,e.width)}drawGradientStroke(t,e){this._hitTestStroke(t,e.width)}drawMarkerLayer(t,e){t.markerPlacement&&("CIMMarkerPlacementInsidePolygon"===t.markerPlacement.type||"CIMMarkerPlacementPolygonCenter"===t.markerPlacement.type&&t.markerPlacement.clipAtBoundary)?this._hitTestFill(e):super.drawMarkerLayer(t,e)}pushClipPath(t){}popClipPath(){}drawImage(t,e){const{url:r}=t,i=t.scaleX??1,o=this._resourceManager.getResource(r);if(s(o)||0===o.height||0===e)return;const n=e*this.geomUnitsPerPoint(),a=n*i*(o.width/o.height),l=this.reverseTransformPt(this._searchPoint),h=this._searchDistPoint;Math.abs(l[0])<a/2+h&&Math.abs(l[1])<n/2+h&&(this._earlyReturn=!0)}drawText(e,r){const i=this._textInfo;if(!i)return;const s=i.get(e);if(!s)return;const{text:o,mosaicItem:n}=s;if(!n||0===n.glyphMosaicItems.length)return;const a=e.height??J,l=tt(e.lineGapType,e.lineGap??0,a),h=t(o)[1],c=n.glyphMosaicItems,m=X(c,h,{scale:a/D,angle:0,xOffset:0,yOffset:0,hAlign:Z(e.horizontalAlignment),vAlign:$(e.verticalAlignment),maxLineWidth:512,lineHeight:G*Math.max(.25,Math.min(l||1,4)),decoration:e.font.decoration||"none",isCIM:!0}),f=this.reverseTransformPt(this._searchPoint),u=f[0],p=f[1];for(const t of m.glyphs)if(u>t.xTopLeft&&u<t.xBottomRight&&p>-t.yBottomRight&&p<-t.yTopLeft){this._earlyReturn=!0;break}}_hitTestFill(t){let e=null;if(_(t)){const r=t;e=[[[r.xmin,r.ymin],[r.xmin,r.ymax],[r.xmax,r.ymax],[r.xmax,r.ymin],[r.xmin,r.ymin]]]}else if(p(t))e=t.rings;else{if(!d(t))return;e=t.paths}const r=this.reverseTransformPt(this._searchPoint);if(this._pointInPolygon(r,e)&&(this._earlyReturn=!0),!this._earlyReturn){const t=this.reverseTransformSize(this._searchDistPoint)*this.geomUnitsPerPoint();this._nearLine(r,e,t)&&(this._earlyReturn=!0)}}_hitTestStroke(t,e){let r=null;if(_(t)){const e=t;r=[[[e.xmin,e.ymin],[e.xmin,e.ymax],[e.xmax,e.ymax],[e.xmax,e.ymin],[e.xmin,e.ymin]]]}else if(p(t))r=t.rings;else{if(!d(t))return;r=t.paths}const i=this.reverseTransformPt(this._searchPoint),s=e*this.geomUnitsPerPoint(),o=this.reverseTransformSize(this._searchDistPoint)*this.geomUnitsPerPoint();this._nearLine(i,r,s/2+o)&&(this._earlyReturn=!0)}_pointInPolygon(t,e){let r=0;for(const i of e){const e=i.length;for(let s=1;s<e;s++){const e=i[s-1],o=i[s];if(e[1]>t[1]==o[1]>t[1])continue;(o[0]-e[0])*(t[1]-e[1])-(o[1]-e[1])*(t[0]-e[0])>0?r++:r--}}return 0!==r}_nearLine(t,e,r){for(const i of e){const e=i.length;for(let s=1;s<e;s++){const e=i[s-1],o=i[s];let n=(o[0]-e[0])*(o[0]-e[0])+(o[1]-e[1])*(o[1]-e[1]);if(0===n)continue;n=Math.sqrt(n);const a=((o[0]-e[0])*(t[1]-e[1])-(o[1]-e[1])*(t[0]-e[0]))/n;if(Math.abs(a)<r){const i=((o[0]-e[0])*(t[0]-e[0])+(o[1]-e[1])*(t[1]-e[1]))/n;if(i>-r&&i<n+r)return!0}}}return!1}}class W extends Y{constructor(t,e,r,i){super(e,r),this._applyAdditionalRenderProps=i,this._colorSubstitutionHelper=new P,this._ctx=t}drawSolidFill(t,e){if(!t)return;if(p(t))this._buildPath(t.rings,!0);else if(d(t))this._buildPath(t.paths,!0);else if(_(t))this._buildPath(Q(t).rings,!0);else{if(!g(t))return;console.log("CanvasDrawHelper.drawSolidFill - No implementation!")}const r=this._ctx;r.fillStyle="string"==typeof e?e:"rgba("+Math.round(e[0])+","+Math.round(e[1])+","+Math.round(e[2])+","+e[3]/255+")",r.fill("evenodd")}drawSolidStroke(t,e,r,i,s,o){if(!t||!e||0===r)return;if(p(t))this._buildPath(t.rings,!0);else if(d(t))this._buildPath(t.paths,!1);else{if(!_(t))return void console.log("CanvasDrawHelper.drawSolidStroke isn't implemented!");this._buildPath(Q(t).rings,!0)}const n=this._ctx;n.strokeStyle="string"==typeof e?e:"rgba("+Math.round(e[0])+","+Math.round(e[1])+","+Math.round(e[2])+","+e[3]/255+")",n.lineWidth=Math.max(this.transformSize(r),.5),this._setCapStyle(i),this._setJoinStyle(s),n.miterLimit=o,n.stroke()}pushClipPath(t){if(this._ctx.save(),p(t))this._buildPath(t.rings,!0);else if(d(t))this._buildPath(t.paths,!0);else{if(!_(t))return;this._buildPath(Q(t).rings,!0)}this._ctx.clip("evenodd")}popClipPath(){this._ctx.restore()}drawImage(t,e){const{colorSubstitutions:r,url:i,tintColor:o}=t,n=t.scaleX??1,a=this._resourceManager.getResource(i);if(s(a))return;let l=e*(a.width/a.height),h=e;e||(l=a.width,h=a.height);const c=I(i)||"src"in a&&I(a.src);let m="getFrame"in a?k(a):a;r&&(m=this._colorSubstitutionHelper.applyColorSubstituition(m,r)),this._applyAdditionalRenderProps&&!c&&o&&(m=this._colorSubstitutionHelper.tintImageData(m,o));const f=this.transformPt([0,0]),[u,p]=this.getTransformAngle(),d=this.transformSize(1),_=this._ctx;_.save(),_.setTransform({m11:n*d*u,m12:n*d*p,m21:-d*p,m22:d*u,m41:f[0],m42:f[1]}),_.drawImage(m,-l/2,-h/2,l,h),_.restore()}drawText(t,e){if(!e||0===e.length)return;this._textRasterizer||(this._textRasterizer=new T);const r=et(t);r.size*=this.transformSize(a(1));const i=this._textRasterizer.rasterizeText(e,r);if(!i)return;const{size:s,anchorX:o,anchorY:n,canvas:l}=i,h=s[0]*(o+.5),c=s[1]*(n-.5),m=this._ctx,f=this.transformPt([0,0]),[u,p]=this.getTransformAngle(),d=1;m.save(),m.setTransform({m11:d*u,m12:d*p,m21:-d*p,m22:d*u,m41:f[0]-d*h,m42:f[1]+d*c}),m.drawImage(l,0,0),m.restore()}drawPictureFill(t,e){if(!t)return;let{colorSubstitutions:r,height:i,offsetX:o,offsetY:n,rotation:a,scaleX:l,tintColor:h,url:c}=e;const m=this._resourceManager.getResource(c);if(s(m))return;if(p(t))this._buildPath(t.rings,!0);else if(d(t))this._buildPath(t.paths,!0);else if(_(t))this._buildPath(Q(t).rings,!0);else{if(!g(t))return;console.log("CanvasDrawHelper.drawPictureFill - No implementation!")}const f=this._ctx,u=I(c)||"src"in m&&I(m.src);let y,P="getFrame"in m?k(m):m;if(r&&(P=this._colorSubstitutionHelper.applyColorSubstituition(P,r)),this._applyAdditionalRenderProps){u||h&&(P=this._colorSubstitutionHelper.tintImageData(P,h)),y=f.createPattern(P,"repeat");const t=this.transformSize(1);a||(a=0),o?o*=t:o=0,n?n*=t:n=0,i&&(i*=t);const e=i?i/m.height:1,r=l&&i?l*i/m.width:1;if(0!==a||1!==e||1!==r||0!==o||0!==n){const t=new DOMMatrix;t.rotateSelf(0,0,-a).translateSelf(o,n).scaleSelf(r,e,1),y.setTransform(t)}}else y=f.createPattern(P,"repeat");f.save(),f.fillStyle=y,f.fill("evenodd"),f.restore()}drawPictureStroke(t,e){if(!t)return;let{colorSubstitutions:i,capStyle:o,joinStyle:n,miterLimit:a,tintColor:h,url:c,width:m}=e;const f=this._resourceManager.getResource(c);if(s(f))return;let u;if(p(t))u=t.rings;else if(d(t))u=t.paths;else if(_(t))u=Q(t).rings;else{if(!g(t))return;console.log("CanvasDrawHelper.drawPictureStroke - No implementation!")}m||(m=f.width);const y=I(c)||"src"in f&&I(f.src);let P="getFrame"in f?k(f):f;i&&(P=this._colorSubstitutionHelper.applyColorSubstituition(P,i)),this._applyAdditionalRenderProps&&(y||h&&(P=this._colorSubstitutionHelper.tintImageData(P,h)));const w=Math.max(this.transformSize(l(m)),.5),x=w/P.width,S=this._ctx,M=S.createPattern(P,"repeat-y");let b,C;S.save(),this._setCapStyle(o),this._setJoinStyle(n),S.miterLimit=a,S.lineWidth=w;for(let s of u)if(s=r(s),it(s),s&&!(s.length<=1)){b=this.transformPt(s[0]);for(let t=1;t<s.length;t++){C=this.transformPt(s[t]);const e=K(b,C),r=new DOMMatrix;r.translateSelf(0,b[1]-w/2).scaleSelf(x,x,1).rotateSelf(0,0,90-e),M.setTransform(r),S.strokeStyle=M,S.beginPath(),S.moveTo(b[0],b[1]),S.lineTo(C[0],C[1]),S.stroke(),b=C}}S.restore()}_buildPath(t,e){const r=this._ctx;if(r.beginPath(),t)for(const i of t){const t=i?i.length:0;if(t>1){let s=this.transformPt(i[0]);r.moveTo(s[0],s[1]);for(let e=1;e<t;e++)s=this.transformPt(i[e]),r.lineTo(s[0],s[1]);e&&r.closePath()}}}_setCapStyle(t){switch(t){case M.Butt:this._ctx.lineCap="butt";break;case M.Round:this._ctx.lineCap="round";break;case M.Square:this._ctx.lineCap="square"}}_setJoinStyle(t){switch(t){case b.Bevel:this._ctx.lineJoin="bevel";break;case b.Round:this._ctx.lineJoin="round";break;case b.Miter:this._ctx.lineJoin="miter"}}}function K(t,e){const r=e[0]-t[0],i=e[1]-t[1];return 180/Math.PI*Math.atan2(i,r)}const Q=t=>t?{spatialReference:t.spatialReference,rings:[[[t.xmin,t.ymin],[t.xmin,t.ymax],[t.xmax,t.ymax],[t.xmax,t.ymin],[t.xmin,t.ymin]]]}:null,Z=t=>{switch(t){case"Left":return H.Left;case"Right":return H.Right;case"Center":return H.Center;case"Justify":return N.warnOnce("Horizontal alignment 'justify' is not implemented. Falling back to 'center'."),H.Center}},$=t=>{switch(t){case"Top":return B.Top;case"Center":return B.Center;case"Bottom":return B.Bottom;case"Baseline":return B.Baseline}},tt=(t,e,r)=>{switch(t){case"ExtraLeading":return 1+e/r;case"Multiple":return e;case"Exact":return e/r}};function et(t,r=1){const i=R(t),s=v(t.fontStyleName),o=e(t.fontFamilyName),{weight:n,style:a}=s,l=r*(t.height||5),h=z(t.horizontalAlignment),c=F(t.verticalAlignment),m=L(t),f=A(t.haloSymbol),u=f?r*(0|t.haloSize):0;return{color:m,size:l,horizontalAlignment:h,verticalAlignment:c,font:{family:o,style:j(a),weight:U(n),decoration:i},halo:{size:u||0,color:f,style:a},pixelRatio:1,premultiplyColors:!0}}const rt=1e-4;function it(t){let e,r,i,s,o,n=t[0],a=1;for(;a<t.length;)e=t[a][0]-n[0],r=t[a][1]-n[1],s=0!==e?r/e:Math.PI/2,void 0!==i&&s-i<=rt?(t.splice(a-1,1),n=o):(o=n,n=t[a],a++),i=s}export{Y as CIMSymbolDrawHelper,E as C_DEG_TO_RAD,W as CanvasDrawHelper,q as EnvDrawHelper,V as HittestDrawHelper,O as Transformation,Z as horizontalAlignment2HAlign,tt as lineGapType2LineHeight,$ as verticalAlignment2VAlign};