/* * (c) Copyright Ascensio System SIA 2010-2024 * * This program is a free software product. You can redistribute it and/or * modify it under the terms of the GNU Affero General Public License (AGPL) * version 3 as published by the Free Software Foundation. In accordance with * Section 7(a) of the GNU AGPL its Section 15 shall be amended to the effect * that Ascensio System SIA expressly excludes the warranty of non-infringement * of any third-party rights. * * This program is distributed WITHOUT ANY WARRANTY; without even the implied * warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. For * details, see the GNU AGPL at: http://www.gnu.org/licenses/agpl-3.0.html * * You can contact Ascensio System SIA at 20A-6 Ernesta Birznieka-Upish * street, Riga, Latvia, EU, LV-1050. * * The interactive user interfaces in modified source and object code versions * of the Program must display Appropriate Legal Notices, as required under * Section 5 of the GNU AGPL version 3. * * Pursuant to Section 7(b) of the License you must retain the original Product * logo when distributing the program. Pursuant to Section 7(e) we decline to * grant you any rights under trademark law for use of our trademarks. * * All the Product's GUI elements, including illustrations and icon sets, as * well as technical writing content are licensed under the terms of the * Creative Commons Attribution-ShareAlike 4.0 International. See the License * terms at http://creativecommons.org/licenses/by-sa/4.0/legalcode * */ "use strict"; (function(window, undefined){ // Import var HitInBezier4 = AscFormat.HitInBezier4; // arcTo new version function Arc3(ctx, fX, fY, fWidth, fHeight, fStartAngle, fSweepAngle, ellipseRotation) { // Params transform var sin1 = Math.sin(fStartAngle); var cos1 = Math.cos(fStartAngle); var __x = cos1 / fWidth; var __y = sin1 / fHeight; var l = 1 / Math.sqrt(__x * __x + __y * __y); var cx = fX - l * cos1; var cy = fY - l * sin1; // ellipseRotation can be undefined in old version calls and it is passed down anyway Arc2(ctx, cx - fWidth, cy - fHeight, 2 * fWidth, 2 * fHeight, fStartAngle, fSweepAngle, ellipseRotation); } function Arc2(ctx, fX, fY, fWidth, fHeight, fStartAngle, fSweepAngle, ellipseRotation) { // Calls Ellipse or EllipseArc if (0 >= fWidth || 0 >= fHeight) return; fStartAngle = -fStartAngle; fSweepAngle = -fSweepAngle; if (false /*is path closed*/ ) { var fStartX = fX + fWidth / 2.0 + fWidth / 2 * Math.cos( AngToEllPrm( fStartAngle, fWidth / 2, fHeight / 2 ) ); var fStartY = fY + fHeight / 2.0 - fHeight / 2 * Math.sin( AngToEllPrm ( fStartAngle, fWidth / 2, fHeight / 2 ) ); if ( fSweepAngle < (2 * Math.PI) ) { ctx._m(fStartX, fStartY); } } var bClockDirection = false; var fEndAngle = (2 * Math.PI) -(fSweepAngle + fStartAngle); var fSrtAngle = (2 * Math.PI) - fStartAngle; // by this moment we have endAngle( = fEndAngle) and startAngle( = fSrtAngle) clockwise if( fSweepAngle > 0 ) bClockDirection = true; if(Math.abs(fSweepAngle) >= (2 * Math.PI)) { Ellipse(ctx, fX + fWidth / 2, fY + fHeight / 2, fWidth / 2, fHeight / 2); } else { EllipseArc(ctx, fX + fWidth / 2, fY + fHeight / 2, fWidth / 2, fHeight / 2, fSrtAngle, fEndAngle, bClockDirection, ellipseRotation); } } function AngToEllPrm(fAngle, fXRad, fYRad) { // to ellipse parametric equation angle parameter - t // https://www.mathopenref.com/coordparamellipse.html return Math.atan2( Math.sin( fAngle ) / fYRad, Math.cos( fAngle ) / fXRad ); } function Ellipse(ctx, fX, fY, fXRad, fYRad) { ctx._m(fX - fXRad, fY); var c_fKappa = 0.552; ctx._c(fX - fXRad, fY + fYRad * c_fKappa, fX - fXRad * c_fKappa, fY + fYRad, fX, fY + fYRad); ctx._c(fX + fXRad * c_fKappa, fY + fYRad, fX + fXRad, fY + fYRad * c_fKappa, fX + fXRad, fY); ctx._c(fX + fXRad, fY - fYRad * c_fKappa, fX + fXRad * c_fKappa, fY - fYRad, fX, fY - fYRad); ctx._c(fX - fXRad * c_fKappa, fY - fYRad, fX - fXRad, fY - fYRad * c_fKappa, fX - fXRad, fY); } function EllipseArc(ctx, fX, fY, fXRad, fYRad, fAngle1, fAngle2, bClockDirection, ellipseRotation) { // If arc comes through 0 angle - splits one to two EllipseArc2 calls while ( fAngle1 < 0 ) fAngle1 += (2 * Math.PI); while ( fAngle1 > (2 * Math.PI) ) fAngle1 -= (2 * Math.PI); while ( fAngle2 < 0 ) fAngle2 += (2 * Math.PI); while ( fAngle2 >= (2 * Math.PI) ) fAngle2 -= (2 * Math.PI); let rotatePoint; // fX = cx, fY = cy, fAngle1 = startAngle, fAngle2 = endAngle // rotatePoint added later for ellipse rotation. it is arc start point. // it is not used if ellipseRotation not used if (ellipseRotation !== undefined) { rotatePoint = {x : fX + fXRad * Math.cos( AngToEllPrm( fAngle1, fXRad, fYRad ) ), y : fY + fYRad * Math.sin( AngToEllPrm( fAngle1, fXRad, fYRad ) )}; } // let rotatePoint = {x : fX - fXRad, y : fY}; if ( !bClockDirection ) { if ( fAngle1 <= fAngle2 ) EllipseArc2(ctx, fX, fY, fXRad, fYRad, fAngle1, fAngle2, false, ellipseRotation, rotatePoint); else { // if arc comes through 0 angle - split it EllipseArc2(ctx, fX, fY, fXRad, fYRad, fAngle1, 2 * Math.PI, false, ellipseRotation, rotatePoint); EllipseArc2(ctx, fX, fY, fXRad, fYRad, 0, fAngle2, false, ellipseRotation, rotatePoint); } } else { if ( fAngle1 >= fAngle2 ) EllipseArc2(ctx, fX, fY, fXRad, fYRad, fAngle1, fAngle2, true, ellipseRotation, rotatePoint); else { // if arc comes through 0 angle - split it EllipseArc2(ctx, fX, fY, fXRad, fYRad, fAngle1, 0, true, ellipseRotation, rotatePoint); EllipseArc2(ctx, fX, fY, fXRad, fYRad, 2 * Math.PI, fAngle2, true, ellipseRotation, rotatePoint); } } } function EllipseArc2(ctx, fX, fY, fXRad, fYRad, dAngle1, dAngle2, bClockDirection, ellipseRotation, rotatePoint) { // Splits calls to EllipseArc3 on each quadrant var nFirstPointQuard = ((2 * dAngle1 / Math.PI) >> 0) + 1; var nSecondPointQuard = ((2 * dAngle2 / Math.PI) >> 0) + 1; nSecondPointQuard = Math.min( 4, Math.max( 1, nSecondPointQuard ) ); nFirstPointQuard = Math.min( 4, Math.max( 1, nFirstPointQuard ) ); // fX = cx, fY = cy, fAngle1 = startAngle, fAngle2 = endAngle var fStartX = fX + fXRad * Math.cos( AngToEllPrm( dAngle1, fXRad, fYRad ) ); var fStartY = fY + fYRad * Math.sin( AngToEllPrm( dAngle1, fXRad, fYRad ) ); var EndPoint = {X: 0, Y: 0}; //ctx._l(fStartX, fStartY); var fCurX = fStartX, fCurY = fStartY; var dStartAngle = dAngle1; var dEndAngle = 0; if ( !bClockDirection ) { for( var nIndex = nFirstPointQuard; nIndex <= nSecondPointQuard; nIndex++ ) { if ( nIndex == nSecondPointQuard ) dEndAngle = dAngle2; else dEndAngle = nIndex * Math.PI / 2; if ( !( nIndex == nFirstPointQuard ) ) dStartAngle = (nIndex - 1 ) * Math.PI / 2; EndPoint = EllipseArc3(ctx, fX, fY, fXRad, fYRad, AngToEllPrm( dStartAngle, fXRad, fYRad ), AngToEllPrm( dEndAngle, fXRad, fYRad ), false, ellipseRotation, rotatePoint); } } else { for( var nIndex = nFirstPointQuard; nIndex >= nSecondPointQuard; nIndex-- ) { if ( nIndex == nFirstPointQuard ) dStartAngle = dAngle1; else dStartAngle = nIndex * Math.PI / 2; if ( !( nIndex == nSecondPointQuard ) ) dEndAngle = (nIndex - 1 ) * Math.PI / 2; else dEndAngle = dAngle2; EndPoint = EllipseArc3(ctx, fX, fY, fXRad, fYRad, AngToEllPrm( dStartAngle, fXRad, fYRad ), AngToEllPrm( dEndAngle, fXRad, fYRad ), false, ellipseRotation, rotatePoint); } } } function EllipseArc3(ctx, fX, fY, fXRad, fYRad, dAngle1, dAngle2, bClockDirection, ellipseRotation, rotatePoint) { // fX = cx, fY = cy, fAngle1 = startAngle after AngToEllPrm, fAngle2 = endAngle after AngToEllPrm var fAlpha = Math.sin( dAngle2 - dAngle1 ) * ( Math.sqrt( 4.0 + 3.0 * Math.tan( (dAngle2 - dAngle1) / 2.0 ) * Math.tan( (dAngle2 - dAngle1) / 2.0 ) ) - 1.0 ) / 3.0; var sin1 = Math.sin(dAngle1); var cos1 = Math.cos(dAngle1); var sin2 = Math.sin(dAngle2); var cos2 = Math.cos(dAngle2); // calculate start point var fX1 = fX + fXRad * cos1; var fY1 = fY + fYRad * sin1; // calculate end point var fX2 = fX + fXRad * cos2; var fY2 = fY + fYRad * sin2; // bezier control point 1 var fCX1 = fX1 - fAlpha * fXRad * sin1; var fCY1 = fY1 + fAlpha * fYRad * cos1; // bezier control point 2 var fCX2 = fX2 + fAlpha * fXRad * sin2; var fCY2 = fY2 - fAlpha * fYRad * cos2; if (ellipseRotation !== undefined) { // https://www.figma.com/file/hs43oiAUyuoqFULVoJ5lyZ/EllipticArcConvert?type=design&node-id=265-2&mode=design&t=pla9h2OkZAde8Xim-0 // ellipseRotation = 0; // TODO import /** * afin rotate clockwise * @param {number} x * @param {number} y * @param {number} radiansRotateAngle radians Rotate AntiClockWise Angle. E.g. 30 degrees rotates does DOWN. * @returns {{x: number, y: number}} point */ function rotatePointAroundCordsStartClockWise(x, y, radiansRotateAngle) { let newX = x * Math.cos(radiansRotateAngle) + y * Math.sin(radiansRotateAngle); let newY = x * (-1) * Math.sin(radiansRotateAngle) + y * Math.cos(radiansRotateAngle); return {x : newX, y: newY}; } let startPointRelative = {x : fX1 - rotatePoint.x, y : rotatePoint.y - fY1}; let endPointRelative = {x : fX2 - rotatePoint.x, y : rotatePoint.y - fY2}; let controlPoint1Relative = {x : fCX1 - rotatePoint.x, y : rotatePoint.y - fCY1}; let controlPoint2Relative = {x : fCX2 - rotatePoint.x, y : rotatePoint.y - fCY2}; let startPointRelativeRotated = rotatePointAroundCordsStartClockWise(startPointRelative.x, startPointRelative.y, ellipseRotation); let endPointRelativeRotated = rotatePointAroundCordsStartClockWise(endPointRelative.x, endPointRelative.y, ellipseRotation); let controlPoint1RelativeRotated = rotatePointAroundCordsStartClockWise(controlPoint1Relative.x, controlPoint1Relative.y, ellipseRotation); let controlPoint2RelativeRotated = rotatePointAroundCordsStartClockWise(controlPoint2Relative.x, controlPoint2Relative.y, ellipseRotation); // go to initial cord system let startPointRotated = {x : startPointRelativeRotated.x + rotatePoint.x, y : rotatePoint.y - startPointRelativeRotated.y}; let endPointRotated = {x : endPointRelativeRotated.x + rotatePoint.x, y : rotatePoint.y - endPointRelativeRotated.y}; let controlPoint1Rotated = {x : controlPoint1RelativeRotated.x + rotatePoint.x, y : rotatePoint.y - controlPoint1RelativeRotated.y}; let controlPoint2Rotated = {x : controlPoint2RelativeRotated.x + rotatePoint.x, y : rotatePoint.y - controlPoint2RelativeRotated.y}; fX1 = startPointRotated.x; fY1 = startPointRotated.y; fX2 = endPointRotated.x; fY2 = endPointRotated.y; fCX1 = controlPoint1Rotated.x; fCY1 = controlPoint1Rotated.y; fCX2 = controlPoint2Rotated.x; fCY2 = controlPoint2Rotated.y; } if ( !bClockDirection ) { ctx._c(fCX1, fCY1, fCX2, fCY2, fX2, fY2); return {X: fX2, Y: fY2}; } else { ctx._c(fCX2, fCY2, fCX1, fCY1, fX1, fY1); return {X: fX1, Y: fY1}; } } // ----------------------------------------------------------------------- // function _ArcToOnCanvas(context, start_x, start_y, width_r, height_r, start_ang, sweep_ang) { var _sin = Math.sin(start_ang); var _cos = Math.cos(start_ang); var _x = _cos / width_r; var _y = _sin / height_r; var _l = 1 / Math.sqrt(_x * _x + _y * _y); var _cx = start_x - _l * _cos; var _cy = start_y - _l * _sin; ArcTo2OnCanvas(context, _cx - width_r, _cy - height_r, 2 * width_r, 2 * height_r, start_ang, sweep_ang); } function ArcTo2OnCanvas(context, _l_c_x, _l_c_y, width, height, start_ang, sweep_ang) { if (0 >= width || 0 >= height) return; start_ang = -start_ang; sweep_ang = -sweep_ang; var bClockDirection = false; var fEndAngle = (2 * Math.PI) - (sweep_ang + start_ang); var fSrtAngle = (2 * Math.PI) - start_ang; if (sweep_ang > 0) { bClockDirection = true; } if (Math.abs(sweep_ang) >= (2 * Math.PI)) { EllipseOnCanvas(context, _l_c_x + width / 2, _l_c_y + height / 2, width / 2, height / 2); } else { EllipseArcOnCanvas(context, _l_c_x + width / 2, _l_c_y + height / 2, width / 2, height / 2, fSrtAngle, fEndAngle, bClockDirection); } } function EllipseOnCanvas(ctx, fX, fY, fXRad, fYRad) { ctx.moveTo(fX - fXRad, fY); var c_fKappa = 0.552; ctx.bezierCurveTo(fX - fXRad, fY + fYRad * c_fKappa, fX - fXRad * c_fKappa, fY + fYRad, fX, fY + fYRad); ctx.bezierCurveTo(fX + fXRad * c_fKappa, fY + fYRad, fX + fXRad, fY + fYRad * c_fKappa, fX + fXRad, fY); ctx.bezierCurveTo(fX + fXRad, fY - fYRad * c_fKappa, fX + fXRad * c_fKappa, fY - fYRad, fX, fY - fYRad); ctx.bezierCurveTo(fX - fXRad * c_fKappa, fY - fYRad, fX - fXRad, fY - fYRad * c_fKappa, fX - fXRad, fY); } function EllipseArcOnCanvas(ctx, fX, fY, fXRad, fYRad, fAngle1, fAngle2, bClockDirection) { while ( fAngle1 < 0 ) fAngle1 += (2 * Math.PI); while ( fAngle1 > (2 * Math.PI) ) fAngle1 -= (2 * Math.PI); while ( fAngle2 < 0 ) fAngle2 += (2 * Math.PI); while ( fAngle2 >= (2 * Math.PI) ) fAngle2 -= (2 * Math.PI); if ( !bClockDirection ) { if ( fAngle1 <= fAngle2 ) EllipseArc2OnCanvas(ctx, fX, fY, fXRad, fYRad, fAngle1, fAngle2, false); else { EllipseArc2OnCanvas(ctx, fX, fY, fXRad, fYRad, fAngle1, 2 * Math.PI, false); EllipseArc2OnCanvas(ctx, fX, fY, fXRad, fYRad, 0, fAngle2, false); } } else { if ( fAngle1 >= fAngle2 ) EllipseArc2OnCanvas(ctx, fX, fY, fXRad, fYRad, fAngle1, fAngle2, true); else { EllipseArc2OnCanvas(ctx, fX, fY, fXRad, fYRad, fAngle1, 0, true); EllipseArc2OnCanvas(ctx, fX, fY, fXRad, fYRad, 2 * Math.PI, fAngle2, true); } } } function EllipseArc2OnCanvas(ctx, fX, fY, fXRad, fYRad, dAngle1, dAngle2, bClockDirection) { var nFirstPointQuard = ((2 * dAngle1 / Math.PI) >> 0) + 1; var nSecondPointQuard = ((2 * dAngle2 / Math.PI) >> 0) + 1; nSecondPointQuard = Math.min( 4, Math.max( 1, nSecondPointQuard ) ); nFirstPointQuard = Math.min( 4, Math.max( 1, nFirstPointQuard ) ); var fStartX = fX + fXRad * Math.cos( AngToEllPrm( dAngle1, fXRad, fYRad ) ); var fStartY = fY + fYRad * Math.sin( AngToEllPrm( dAngle1, fXRad, fYRad ) ); var EndPoint = {X: 0, Y: 0}; ctx.lineTo(fStartX, fStartY); var fCurX = fStartX, fCurY = fStartY; var dStartAngle = dAngle1; var dEndAngle = 0; if ( !bClockDirection ) { for( var nIndex = nFirstPointQuard; nIndex <= nSecondPointQuard; nIndex++ ) { if ( nIndex == nSecondPointQuard ) dEndAngle = dAngle2; else dEndAngle = nIndex * Math.PI / 2; if ( !( nIndex == nFirstPointQuard ) ) dStartAngle = (nIndex - 1 ) * Math.PI / 2; EndPoint = EllipseArc3OnCanvas(ctx, fX, fY, fXRad, fYRad, AngToEllPrm( dStartAngle, fXRad, fYRad ), AngToEllPrm( dEndAngle, fXRad, fYRad ), false); } } else { for( var nIndex = nFirstPointQuard; nIndex >= nSecondPointQuard; nIndex-- ) { if ( nIndex == nFirstPointQuard ) dStartAngle = dAngle1; else dStartAngle = nIndex * Math.PI / 2; if ( !( nIndex == nSecondPointQuard ) ) dEndAngle = (nIndex - 1 ) * Math.PI / 2; else dEndAngle = dAngle2; EndPoint = EllipseArc3OnCanvas(ctx, fX, fY, fXRad, fYRad, AngToEllPrm( dStartAngle, fXRad, fYRad ), AngToEllPrm( dEndAngle, fXRad, fYRad ), false); } } } function EllipseArc3OnCanvas(ctx, fX, fY, fXRad, fYRad, dAngle1, dAngle2, bClockDirection) { var fAlpha = Math.sin( dAngle2 - dAngle1 ) * ( Math.sqrt( 4.0 + 3.0 * Math.tan( (dAngle2 - dAngle1) / 2.0 ) * Math.tan( (dAngle2 - dAngle1) / 2.0 ) ) - 1.0 ) / 3.0; var sin1 = Math.sin(dAngle1); var cos1 = Math.cos(dAngle1); var sin2 = Math.sin(dAngle2); var cos2 = Math.cos(dAngle2); var fX1 = fX + fXRad * cos1; var fY1 = fY + fYRad * sin1; var fX2 = fX + fXRad * cos2; var fY2 = fY + fYRad * sin2; var fCX1 = fX1 - fAlpha * fXRad * sin1; var fCY1 = fY1 + fAlpha * fYRad * cos1; var fCX2 = fX2 + fAlpha * fXRad * sin2; var fCY2 = fY2 - fAlpha * fYRad * cos2; if ( !bClockDirection ) { ctx.bezierCurveTo(fCX1, fCY1, fCX2, fCY2, fX2, fY2); return {X: fX2, Y: fY2}; } else { ctx.bezierCurveTo(fCX2, fCY2, fCX1, fCY1, fX1, fY1); return {X: fX1, Y: fY1}; } } function _HitToArc(context, px, py, start_x, start_y, width_r, height_r, start_ang, sweep_ang) { var _sin = Math.sin(start_ang); var _cos = Math.cos(start_ang); var _x = _cos / width_r; var _y = _sin / height_r; var _l = 1 / Math.sqrt(_x * _x + _y * _y); var _cx = start_x - _l * _cos; var _cy = start_y - _l * _sin; return HitToArc2(px, py, context, _cx - width_r, _cy - height_r, 2 * width_r, 2 * height_r, start_ang, sweep_ang); } function HitToArc2(px, py, context, _l_c_x, _l_c_y, width, height, start_ang, sweep_ang) { if (0 >= width || 0 >= height) return; start_ang = -start_ang; sweep_ang = -sweep_ang; var bClockDirection = false; var fEndAngle = (2 * Math.PI) - (sweep_ang + start_ang); var fSrtAngle = (2 * Math.PI) - start_ang; if (sweep_ang > 0) { bClockDirection = true; } if (Math.abs(sweep_ang) >= (2 * Math.PI)) { return HitToEllipseOnCanvas(px, py, context, _l_c_x + width / 2, _l_c_y + height / 2, width / 2, height / 2); } else { return HitToEllipseArcOnCanvas(px, py, context, _l_c_x + width / 2, _l_c_y + height / 2, width / 2, height / 2, fSrtAngle, fEndAngle, bClockDirection); } } function HitToEllipseOnCanvas(px, py, ctx, fX, fY, fXRad, fYRad) { var c_fKappa = 0.552; return HitInBezier4(ctx, px, py, fX - fXRad, fY, fX - fXRad, fY + fYRad * c_fKappa, fX - fXRad * c_fKappa, fY + fYRad, fX, fY + fYRad) || HitInBezier4(ctx, px, py, fX, fY + fYRad, fX + fXRad * c_fKappa, fY + fYRad, fX + fXRad, fY + fYRad * c_fKappa, fX + fXRad, fY)|| HitInBezier4(ctx, px, py, fX + fXRad, fY, fX + fXRad, fY - fYRad * c_fKappa, fX + fXRad * c_fKappa, fY - fYRad, fX, fY - fYRad)|| HitInBezier4(ctx, px, py, fX, fY - fYRad, fX - fXRad * c_fKappa, fY - fYRad, fX - fXRad, fY - fYRad * c_fKappa, fX - fXRad, fY); } function HitToEllipseArcOnCanvas(px, py, ctx, fX, fY, fXRad, fYRad, fAngle1, fAngle2, bClockDirection) { while ( fAngle1 < 0 ) fAngle1 += (2 * Math.PI); while ( fAngle1 > (2 * Math.PI) ) fAngle1 -= (2 * Math.PI); while ( fAngle2 < 0 ) fAngle2 += (2 * Math.PI); while ( fAngle2 >= (2 * Math.PI) ) fAngle2 -= (2 * Math.PI); if ( !bClockDirection ) { if ( fAngle1 <= fAngle2 ) return HitToEllipseArc2OnCanvas(px, py,ctx, fX, fY, fXRad, fYRad, fAngle1, fAngle2, false); else { return HitToEllipseArc2OnCanvas(px, py,ctx, fX, fY, fXRad, fYRad, fAngle1, 2 * Math.PI, false)|| HitToEllipseArc2OnCanvas(px, py,ctx, fX, fY, fXRad, fYRad, 0, fAngle2, false); } } else { if ( fAngle1 >= fAngle2 ) return HitToEllipseArc2OnCanvas(px, py,ctx, fX, fY, fXRad, fYRad, fAngle1, fAngle2, true); else { return HitToEllipseArc2OnCanvas(px, py, ctx, fX, fY, fXRad, fYRad, fAngle1, 0, true) || HitToEllipseArc2OnCanvas(px, py,ctx, fX, fY, fXRad, fYRad, 2 * Math.PI, fAngle2, true); } } } function HitToEllipseArc2OnCanvas(px, py, ctx, fX, fY, fXRad, fYRad, dAngle1, dAngle2, bClockDirection) { var nFirstPointQuard = ((2 * dAngle1 / Math.PI) >> 0) + 1; var nSecondPointQuard = ((2 * dAngle2 / Math.PI) >> 0) + 1; nSecondPointQuard = Math.min( 4, Math.max( 1, nSecondPointQuard ) ); nFirstPointQuard = Math.min( 4, Math.max( 1, nFirstPointQuard ) ); var fStartX = fX + fXRad * Math.cos( AngToEllPrm( dAngle1, fXRad, fYRad ) ); var fStartY = fY + fYRad * Math.sin( AngToEllPrm( dAngle1, fXRad, fYRad ) ); var EndPoint = {X: fStartX, Y: fStartY, hit : false}; var dStartAngle = dAngle1; var dEndAngle = 0; if ( !bClockDirection ) { for( var nIndex = nFirstPointQuard; nIndex <= nSecondPointQuard; nIndex++ ) { if ( nIndex == nSecondPointQuard ) dEndAngle = dAngle2; else dEndAngle = nIndex * Math.PI / 2; if ( !( nIndex == nFirstPointQuard ) ) dStartAngle = (nIndex - 1 ) * Math.PI / 2; EndPoint = HitToEllipseArc3OnCanvas(px, py, EndPoint, ctx, fX, fY, fXRad, fYRad, AngToEllPrm( dStartAngle, fXRad, fYRad ), AngToEllPrm( dEndAngle, fXRad, fYRad ), false); if(EndPoint.hit) { return true; } } } else { for( var nIndex = nFirstPointQuard; nIndex >= nSecondPointQuard; nIndex-- ) { if ( nIndex == nFirstPointQuard ) dStartAngle = dAngle1; else dStartAngle = nIndex * Math.PI / 2; if ( !( nIndex == nSecondPointQuard ) ) dEndAngle = (nIndex - 1 ) * Math.PI / 2; else dEndAngle = dAngle2; EndPoint = HitToEllipseArc3OnCanvas(px, py, EndPoint, ctx, fX, fY, fXRad, fYRad, AngToEllPrm( dStartAngle, fXRad, fYRad ), AngToEllPrm( dEndAngle, fXRad, fYRad ), false); if(EndPoint.hit) { return true; } } } return false; } function HitToEllipseArc3OnCanvas(px, py, EndPoint, ctx, fX, fY, fXRad, fYRad, dAngle1, dAngle2, bClockDirection) { var fAlpha = Math.sin( dAngle2 - dAngle1 ) * ( Math.sqrt( 4.0 + 3.0 * Math.tan( (dAngle2 - dAngle1) / 2.0 ) * Math.tan( (dAngle2 - dAngle1) / 2.0 ) ) - 1.0 ) / 3.0; var sin1 = Math.sin(dAngle1); var cos1 = Math.cos(dAngle1); var sin2 = Math.sin(dAngle2); var cos2 = Math.cos(dAngle2); var fX1 = fX + fXRad * cos1; var fY1 = fY + fYRad * sin1; var fX2 = fX + fXRad * cos2; var fY2 = fY + fYRad * sin2; var fCX1 = fX1 - fAlpha * fXRad * sin1; var fCY1 = fY1 + fAlpha * fYRad * cos1; var fCX2 = fX2 + fAlpha * fXRad * sin2; var fCY2 = fY2 - fAlpha * fYRad * cos2; if ( !bClockDirection ) { return {X: fX2, Y: fY2, hit : HitInBezier4(ctx, px, py,EndPoint.X, EndPoint.Y, fCX1, fCY1, fCX2, fCY2, fX2, fY2)}; } else { return {X: fX1, Y: fY1, hit : HitInBezier4(ctx, px, py,EndPoint.X, EndPoint.Y, fCX2, fCY2, fCX1, fCY1, fX1, fY1)}; } } //--------------------------------------------------------export---------------------------------------------------- window['AscFormat'] = window['AscFormat'] || {}; window['AscFormat'].ArcToCurvers = Arc3; window['AscFormat'].HitToArc = _HitToArc; window['AscFormat'].ArcToOnCanvas = _ArcToOnCanvas; window['AscFormat'].EllipseOnCanvas = EllipseOnCanvas; })(window);