/////////////////////////////////////////////////////////////////////////////// // Copyright (C) 2002-2025, Open Design Alliance (the "Alliance"). // All rights reserved. // // This software and its documentation and related materials are owned by // the Alliance. The software may only be incorporated into application // programs owned by members of the Alliance, subject to a signed // Membership Agreement and Supplemental Software License Agreement with the // Alliance. The structure and organization of this software are the valuable // trade secrets of the Alliance and its suppliers. The software is also // protected by copyright law and international treaty provisions. Application // programs incorporating this software must include the following statement // with their copyright notices: // // This application incorporates Open Design Alliance software pursuant to a license // agreement with Open Design Alliance. // Open Design Alliance Copyright (C) 2002-2025 by Open Design Alliance. // All rights reserved. // // By use of this software, its documentation or related materials, you // acknowledge and accept the above terms. /////////////////////////////////////////////////////////////////////////////// #include "OdaCommon.h" #include "SrConicSectionEllipseHelpers.h" #include "SrArcDrawerBase.h" namespace OdSrConicSectionEllipseHelpers { // Returns the octant number of a point of interest on a conic curve. // Arguments dfdx and dfdy specify the x and y components of the // gradient at this point. The return value is an octant number in // the range 1 to 8. // OdInt64 GetOctant(OdInt64 dfdx, OdInt64 dfdy) { OdInt64 oct = 0; if (dfdx < 0) { oct = 7; dfdx = -dfdx; } if (dfdy > 0) { oct ^= 3; dfdy = -dfdy; } if (dfdx > -dfdy) { oct ^= 1; } return ++oct; } bool isOctantBetween(OdInt64 octant, OdInt64 left, OdInt64 right, double startAngle, double endAngle) { if (left == right && endAngle < startAngle) return true; if (octant >= left && octant <= right) return true; if (right - left < 0 && (left <= octant || octant <= right)) return true; return false; } bool isOctantToBeDrawn(OdInt64 octant, OdInt64 start, OdInt64 end, OdInt64 startByDrawing, double startAngle, double endAngle) { if (startAngle == endAngle) return true; auto octantTrimmed = (octant - 1) % 8 + 1; bool isCounterclockwise = startAngle < endAngle; bool isOverlapped = octantTrimmed == startByDrawing; if (isOverlapped && (!isCounterclockwise && OdaPI2 <= endAngle)) return true; return isOctantBetween(octantTrimmed, end, start, startAngle, endAngle); } OdInt64 CalcOctant(OdSrPixelPoint64 origin, OdSrPixelPoint64 point, OdInt64 A, OdInt64 B, OdInt64 C, OdInt64 D, OdInt64 E, OdInt64 /*F*/) { // Determine whether to draw all 8 octants or just an arc if (origin.x != point.x || origin.y != point.y) { // Draw just an arc auto x = point.x - origin.x; // origin at (xs,ys) auto y = point.y - origin.y; auto dSdx = 2 * A * x + B * y + D; // gradient at end point auto dSdy = B * x + 2 * C * y + E; return GetOctant(dSdx, dSdy); } return GetOctant(D, E); } OdInt64 CalcPixelCount(OdInt64 octant, OdInt64 x1, OdInt64 y1, OdInt64 x2, OdInt64 y2) { if (octant & 2) // terminate in octant 2, 3, 6 or 7 return abs(y2 - y1); else // terminate in octant 1, 4, 5 or 8 return abs(x2 - x1); // should we plus 1 to the difference? } OctantStatus getOctantStatus(OdInt64 octant, OdInt64 octantStart, OdInt64 octantEnd, OdInt64 octantOrigin, OdInt64 x, OdInt64 y, OdSrPixelPoint64 start, OdSrPixelPoint64 end, double startAngle, double endAngle, OdInt64& borderFirst, OdInt64& borderSecond) { if (!isOctantToBeDrawn(octant, octantStart, octantEnd, octantOrigin, startAngle, endAngle)) return NotDrawn; OdInt64 octantTrimmed = (octant - 1) % 8 + 1; //bool isFirst = octant == octantTrimmed; if (octantTrimmed != octantStart && octantTrimmed != octantEnd || startAngle == endAngle) return FullyDrawn; if (octant == octantOrigin) { bool isPositiveDirection = startAngle <= endAngle; if (octantTrimmed == octantEnd && !isPositiveDirection && OdaPI2 <= endAngle) return FullyDrawn; if (octantTrimmed == octantStart && octantTrimmed == octantEnd) { if (startAngle <= OdaPI2 && OdaPI2 < endAngle) { borderFirst = CalcPixelCount(octant, x, y, start.x, start.y); borderSecond = -1; return ParticularlyDrawnWithStoppingInFirstBorder; } if (startAngle >= OdaPI2 && OdaPI2 >= endAngle) { borderFirst = CalcPixelCount(octant, x, y, end.x, end.y); borderSecond = -1; return ParticularlyDrawnWithStartingInFirstBorder; } } if (octantTrimmed == octantStart && startAngle >= OdaPI2) { return NotDrawn; } } if (octantTrimmed == octantStart && octantTrimmed == octantEnd) { auto startEndDiff = CalcPixelCount(octant, start.x, start.y, end.x, end.y); if (startAngle < endAngle) { auto endDiff = CalcPixelCount(octant, x, y, end.x, end.y); borderFirst = endDiff; borderSecond = endDiff + startEndDiff; return ParticularlyDrawnInsideBorders; } else { auto startDiff = CalcPixelCount(octant, x, y, start.x, start.y); borderFirst = startDiff; borderSecond = startDiff + startEndDiff; return ParticularlyDrawnOutsideBorders; } } if (octantTrimmed == octantEnd) { borderFirst = CalcPixelCount(octant, x, y, end.x, end.y); borderSecond = -1; return ParticularlyDrawnWithStartingInFirstBorder; } if (octantTrimmed == octantStart) { borderFirst = CalcPixelCount(octant, x, y, start.x, start.y); borderSecond = -1; return ParticularlyDrawnWithStoppingInFirstBorder; } ODA_ASSERT(false); return NotDrawn; } bool checkPixelToBeDrawn(OctantStatus status, OdInt64 pixelCounter, OdInt64 borderFirst, OdInt64 borderSecond) { switch (status) { case NotDrawn: return false; case ParticularlyDrawnInsideBorders: return pixelCounter >= borderFirst && pixelCounter <= borderSecond; case ParticularlyDrawnOutsideBorders: return pixelCounter <= borderFirst || pixelCounter >= borderSecond; case ParticularlyDrawnWithStartingInFirstBorder: return pixelCounter >= borderFirst; case ParticularlyDrawnWithStoppingInFirstBorder: return pixelCounter <= borderFirst; case FullyDrawn: return true; default: ODA_ASSERT(false); return false; } } };