/////////////////////////////////////////////////////////////////////////////// // 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. /////////////////////////////////////////////////////////////////////////////// #ifndef OD_SR_ARC_DRAWER_BASE #define OD_SR_ARC_DRAWER_BASE #include "OdaCommon.h" #include "OdError.h" #include "OdRound.h" #include #include #include #include "SrConicSectionEllipseHelpers.h" #define sgn(x) \ ((x > 0.0) - (x < 0.0)) struct OdSrPixelPoint64 { OdSrPixelPoint64() = default; OdSrPixelPoint64(OdInt64 iX, OdInt64 iY) : x(iX), y(iY), m_initialized(true) {} OdInt64 x = -1; OdInt64 y = -1; bool initialized() { return m_initialized; } private: bool m_initialized = false; }; struct OdSrPixelPoint { OdSrPixelPoint() = default; OdSrPixelPoint(int iX, int iY) : x(iX), y(iY), m_initialized(true) {} int x = -1; int y = -1; bool initialized() { return m_initialized; } private: bool m_initialized = false; }; template class OdSrLineDrawerBase { public: void countPixel(int x, int y) { static_cast(this)->countPixel(x, y); } void drawLine(int x0, int y0, int x1, int y1) { int dx = std::abs(x1 - x0); int dy = std::abs(y1 - y0); int s1 = sgn(x1 - x0); int s2 = sgn(y1 - y0); int swap = 0, temp; if (dy > dx) { temp = dx; dx = dy; dy = temp; swap = 1; } int d = 2 * dy - dx; int x = x0; int y = y0; for (int idx = 0; idx < dx; ++idx) { countPixel(x, y); while (d >= 0) { if (swap) x = x + s1; else y = y + s2; d = d - 2 * dx; } if (swap) y = y + s2; else x = x + s1; d = d + 2 * dy; } } }; class OdSrFrameContext; struct SidePointPair { SidePointPair(const OdGePoint2d& iStart, const OdGePoint2d& iEnd, const OdGePoint2d& iCenter) : start(iStart), end(iEnd), center(iCenter) {} OdGePoint2d start; OdGePoint2d end; OdGePoint2d center; }; template class OdSrArcDrawer { void plotPixel(int x, int y, int& outX, int& outY) { countPixel(x, y); outX = x; outY = y; } public: OdSrArcDrawer(OdSrFrameContext* context, const SidePointPair& sidePoints, ODCOLORREF color) : m_context(context), m_sidePoints(sidePoints), m_color(color) {} void countPixel(int x, int y) { static_cast(this)->countPixel(x, y); } void afterDrawing(const OdSrPixelPoint& center, const OdSrPixelPoint& start, const OdSrPixelPoint& end) { static_cast(this)->afterDrawing(center, start, end); } inline void plotPixelOctant(int x0, int y0, int x, int y, int octant, int& outX, int& outY) { octant = octant % 8; switch (octant) { case 6: plotPixel(x0 + x, y0 + y, outX, outY); break; case 5: plotPixel(x0 - x, y0 + y, outX, outY); break; case 1: plotPixel(x0 + x, y0 - y, outX, outY); break; case 2: plotPixel(x0 - x, y0 - y, outX, outY); break; case 7: plotPixel(x0 + y, y0 + x, outX, outY); break; case 4: plotPixel(x0 - y, y0 + x, outX, outY); break; case 0: plotPixel(x0 + y, y0 - x, outX, outY); break; case 3: plotPixel(x0 - y, y0 - x, outX, outY); break; } } enum BoundType { None, StartByDrawing, EndByDrawing }; void drawCircular(const OdGePoint2d& center, double radius, double startAngle, double endAngle) { startAngle = OdSrConicSectionEllipseHelpers::wrapAngle(startAngle); endAngle = OdSrConicSectionEllipseHelpers::wrapAngle(endAngle); int startOctant = OdSrConicSectionEllipseHelpers::determineOctant(startAngle, true /*isStart*/); int endOctant = OdSrConicSectionEllipseHelpers::determineOctant(endAngle, false /*isStart*/); OdInt32 startCos = (OdInt32)OdRound(Od_abs(cos(startAngle)) * radius); OdInt32 startSin = (OdInt32)OdRound(Od_abs(sin(startAngle)) * radius); OdInt32 endCos = (OdInt32)OdRound(Od_abs(cos(endAngle)) * radius); OdInt32 endSin = (OdInt32)OdRound(Od_abs(sin(endAngle)) * radius); int x; int y; int decisionParameter; int centerX = (OdInt32)OdRound(center.x); int centerY = (OdInt32)OdRound(center.y); int radiusInt = (OdInt32)OdRound(radius); if (endOctant < startOctant || startOctant == endOctant && endAngle < startAngle) { endOctant = endOctant + 8; } OdSrPixelPoint startPixel; OdSrPixelPoint endPixel; OdSrPixelPoint centerPixel(centerX, centerY); for (int idxOctant = startOctant; idxOctant <= endOctant; ++idxOctant) { bool isEven = idxOctant % 2 == 0; int startBoundX = idxOctant % 4 == 1 || idxOctant % 4 == 2 ? startCos : startSin; int startBoundY = idxOctant % 4 == 1 || idxOctant % 4 == 2 ? startSin : startCos; int endBoundX = idxOctant % 4 == 1 || idxOctant % 4 == 2 ? endCos : endSin; int endBoundY = idxOctant % 4 == 1 || idxOctant % 4 == 2 ? endSin : endCos; x = 0; y = radiusInt; int startX = 0; int startY = radiusInt; int endX = -1; int endY = -1; BoundType startBound = BoundType::None; BoundType endBound = BoundType::None; if (idxOctant == startOctant) { if (isEven) { startX = startBoundX; startY = startBoundY; startBound = BoundType::StartByDrawing; } else { endX = startBoundX; endY = startBoundY; startBound = BoundType::EndByDrawing; } } if (idxOctant == endOctant) { if (isEven) { endX = endBoundX; endY = endBoundY; endBound = BoundType::EndByDrawing; } else { startX = endBoundX; startY = endBoundY; endBound = BoundType::StartByDrawing; } } decisionParameter = -2 * radiusInt; while (true) { int oX = -1, oY = -1; if (x >= startX && y <= startY) { plotPixelOctant(centerX, centerY, x, y, idxOctant, oX, oY); if (startBound == BoundType::StartByDrawing && !startPixel.initialized()) { startPixel = OdSrPixelPoint(oX, oY); } if (endBound == BoundType::StartByDrawing && !endPixel.initialized()) { endPixel = OdSrPixelPoint(oX, oY); } } x++; if (decisionParameter > 0) { y--; decisionParameter = decisionParameter + 4 * (x - y) + 10; } else decisionParameter = decisionParameter + 4 * x + 6; if (!(endX == -1 ? (y >= x) : (x <= endX && y >= endY))) { if (startBound == BoundType::EndByDrawing) { startPixel = OdSrPixelPoint(oX, oY); } if (endBound == BoundType::EndByDrawing) { endPixel = OdSrPixelPoint(oX, oY); } break; } } } afterDrawing(centerPixel, startPixel, endPixel); } void drawEllipse(const OdGePoint2d& center, const OdGePoint2d& majorPoint, const OdGePoint2d& minorPoint, const OdGePoint2d& startPoint, const OdGePoint2d& endPoint, double startAngle, double endAngle); #undef plotPixel protected: OdSrFrameContext* m_context; const SidePointPair& m_sidePoints; ODCOLORREF m_color; private: void Conic(OdSrPixelPoint64 origin, OdSrPixelPoint64 start, OdSrPixelPoint64 end, double startAngle, double endAngle, OdInt64 A, OdInt64 B, OdInt64 C, OdInt64 D, OdInt64 E, OdInt64 F); }; #include "SrConicSectionEllipse.hpp" #endif // OD_SR_ARC_DRAWER_BASE