/////////////////////////////////////////////////////////////////////////////// // 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 #define OD_SR_ARC_DRAWER #include #include "SrArcDrawerBase.h" #include "SrConicSectionEllipseHelpers.h" #include #include #include #include #include class OdSrFrameContext; class OdSrDrawedPixelsBucket : public std::set { public: int left() { // actually there's no chance that it's empty so such way is safe return *this->begin(); } int right() { return *this->rbegin(); } }; class OdSrDrawedPixelsInLine { public: enum Mark { Circumference, FirstBorder, SecondBorder, }; OdSrDrawedPixelsInLine() = default; bool initialized() { return m_commonBucket.size() > 0; } void append(int iValue, Mark iMark) { m_commonBucket.insert(iValue); bucketsByMark[iMark].insert(iValue); } void bucketsFilteredSequence(OdArray& buckets) { buckets.resize(0); buckets.reserve(static_cast(bucketsByMark.size())); static const std::array markSequence{ { Mark::Circumference, Mark::FirstBorder, Mark::SecondBorder, Mark::Circumference } }; for (auto mark : markSequence) { if (bucketsByMark.count(mark) == 0) continue; auto& bucket = bucketsByMark.at(mark); if (bucket.size() == 0) continue; buckets.append(bucket); } for (unsigned int idx = 1; idx < buckets.size(); ++idx) { if (buckets[idx - 1].right() >= buckets[idx].left() - 1) { buckets[idx].insert(buckets[idx - 1].begin(), buckets[idx - 1].end()); buckets.removeAt(idx - 1); --idx; } } } int globalLeft() { return m_commonBucket.left(); } int globalRight() { return m_commonBucket.right(); } private: OdSrDrawedPixelsBucket m_commonBucket; std::map bucketsByMark; }; template class OdSrArcDrawerFilled : public OdSrArcDrawer, public OdSrLineDrawerBase { using Mark = OdSrDrawedPixelsInLine::Mark; public: OdSrArcDrawerFilled(OdSrFrameContext* context, const SidePointPair& sidePoints, ODCOLORREF color) : OdSrArcDrawer(context, sidePoints, color){}; void countPixel(int x, int y) { storageYX[y].append(x, m_currentMark); } void setCurrentMark(Mark iMark) { m_currentMark = iMark; } protected: void drawHorizontalLine(int y, int x1, int x2) { OdSrArcDrawer::m_context->draw_horizontalLine(y, x1, x2, OdSrArcDrawer::m_color); } Mark m_currentMark = Mark::Circumference; std::unordered_map storageYX; }; class OdSrArcDrawerFilledByChord : public OdSrArcDrawerFilled { public: OdSrArcDrawerFilledByChord(OdSrFrameContext* context, const SidePointPair& sidePoints, ODCOLORREF color) : OdSrArcDrawerFilled(context, sidePoints, color){}; void afterDrawing(const OdSrPixelPoint& /*center*/, const OdSrPixelPoint& start, const OdSrPixelPoint& end) { drawLine(start.x, start.y, end.x, end.y); for (auto pair : storageYX) if (pair.second.initialized()) drawHorizontalLine(OdSrArcDrawerFilled::m_context->heightInternal() - pair.first, pair.second.globalLeft(), pair.second.globalRight()); } }; class OdSrArcDrawerFilledBySector : public OdSrArcDrawerFilled { public: OdSrArcDrawerFilledBySector(OdSrFrameContext* context, const SidePointPair& sidePoints, ODCOLORREF color) : OdSrArcDrawerFilled(context, sidePoints, color){}; void afterDrawing(const OdSrPixelPoint& center, const OdSrPixelPoint& start, const OdSrPixelPoint& end) { setCurrentMark(start.x < end.x ? OdSrDrawedPixelsInLine::FirstBorder : OdSrDrawedPixelsInLine::SecondBorder); drawLine(center.x, center.y, start.x, start.y); setCurrentMark(start.x < end.x ? OdSrDrawedPixelsInLine::SecondBorder : OdSrDrawedPixelsInLine::FirstBorder); drawLine(center.x, center.y, end.x, end.y); setCurrentMark(OdSrDrawedPixelsInLine::Circumference); OdArray buckets; for (auto pair : storageYX) { if (pair.second.initialized()) { pair.second.bucketsFilteredSequence(buckets); if (buckets.size() == 1) { drawHorizontalLine(OdSrArcDrawerFilled::m_context->heightInternal() - pair.first, buckets[0].left(), buckets[0].right()); continue; } unsigned int idx = 0; if (buckets.size() % 2 != 0) idx = 1; for (; idx < buckets.size() - 1; idx += 2) drawHorizontalLine(OdSrArcDrawerFilled::m_context->heightInternal() - pair.first, buckets[idx].left(), buckets[idx + 1].right()); } } } }; template class OdSrArcDrawerClosed : public OdSrArcDrawer, public OdSrLineDrawerBase { public: OdSrArcDrawerClosed(OdSrFrameContext* context, const SidePointPair& sidePoints, ODCOLORREF color) : OdSrArcDrawer(context, sidePoints, color){}; void countPixel(int x, int y) { OdSrArcDrawer::m_context->draw_point(x, y, OdSrArcDrawer::m_color); } }; class OdSrArcDrawerClosedByChord : public OdSrArcDrawerClosed { public: OdSrArcDrawerClosedByChord(OdSrFrameContext* context, const SidePointPair& sidePoints, ODCOLORREF color) : OdSrArcDrawerClosed(context, sidePoints, color){}; void afterDrawing(const OdSrPixelPoint& /*center*/, const OdSrPixelPoint& start, const OdSrPixelPoint& end) { drawLine(start.x, start.y, end.x, end.y); } }; class OdSrArcDrawerClosedBySector : public OdSrArcDrawerClosed { public: OdSrArcDrawerClosedBySector(OdSrFrameContext* context, const SidePointPair& sidePoints, ODCOLORREF color) : OdSrArcDrawerClosed(context, sidePoints, color){}; void afterDrawing(const OdSrPixelPoint& center, const OdSrPixelPoint& start, const OdSrPixelPoint& end) { drawLine(center.x, center.y, start.x, start.y); drawLine(center.x, center.y, end.x, end.y); } }; class OdSrArcDrawerUnclosed : public OdSrArcDrawer { public: OdSrArcDrawerUnclosed(OdSrFrameContext* context, const SidePointPair& sidePoints, ODCOLORREF color) : OdSrArcDrawer(context, sidePoints, color){}; void countPixel(int x, int y) { OdSrArcDrawer::m_context->draw_point(x, y, OdSrArcDrawer::m_color); } void afterDrawing(const OdSrPixelPoint& /*center*/, const OdSrPixelPoint& /*start*/, const OdSrPixelPoint& /*end*/) { //empty } }; #endif // OD_SR_ARC_DRAWER