#include"ellipse.h"#include"base_helpers.h"#include"device/graphic_device.h"#include"point.h"#define PREANNOUNCE \ PointBaseType __x = 0; \ PointBaseType __y = 0#define DRAW_OFFSET_POINT(offsetx, offsety) \ do { \ __x = ellipse->center.x + (offsetx); \ __y = ellipse->center.y + (offsety); \ setPixel(handler, __x, __y); \ } while (0)#define SQUARE(X) ((X) * (X))staticinlinevoidclearBound(CFBD_GraphicDevice*handler,CFBD_GraphicEllipse*ellipse,constint16_tx_radius,constint16_ty_radius){int32_tlx=asInt32_t(ellipse->center.x)-x_radius;int32_tty=asInt32_t(ellipse->center.y)-y_radius;int32_trx=asInt32_t(ellipse->center.x)+x_radius;int32_tby=asInt32_t(ellipse->center.y)+y_radius;handler->ops->update_area(handler,clamp_u16_from_i32(lx),clamp_u16_from_i32(ty),clamp_u16_from_i32(rx-lx+1),clamp_u16_from_i32(by-ty+1));}voidCFBDGraphic_DrawEllipse(CFBD_GraphicDevice*handler,CFBD_GraphicEllipse*ellipse){PREANNOUNCE;CFBD_Bool(*setPixel)(CFBD_GraphicDevice*device,uint16_tx,uint16_ty)=handler->ops->setPixel;constint16_tx_radius=ellipse->X_Radius;constint16_ty_radius=ellipse->Y_Radius;clearBound(handler,ellipse,x_radius,y_radius);// Bresenham's Ellipse Algorithm to avoid costly floating point calculations// Reference: https://blog.csdn.net/myf_666/article/details/128167392int16_tx=0;int16_ty=y_radius;constint16_ty_radius_square=SQUARE(y_radius);constint16_tx_radius_square=SQUARE(x_radius);// Initial decision variable for the first region of the ellipsefloatd1=y_radius_square+x_radius_square*(-y_radius+0.5);// Draw initial points on the ellipse (4 points due to symmetry)DRAW_OFFSET_POINT(x,y);DRAW_OFFSET_POINT(-x,-y);DRAW_OFFSET_POINT(-x,y);DRAW_OFFSET_POINT(x,-y);// Draw the middle part of the ellipse (first region)while(y_radius_square*(x+1)<x_radius_square*(y-0.5)){if(d1<=0){// Next point is to the east of the current pointd1+=y_radius_square*(2*x+3);}else{// Next point is southeast of the current pointd1+=y_radius_square*(2*x+3)+x_radius_square*(-2*y+2);y--;}x++;// Draw ellipse arc for each point in the current regionDRAW_OFFSET_POINT(x,y);DRAW_OFFSET_POINT(-x,-y);DRAW_OFFSET_POINT(-x,y);DRAW_OFFSET_POINT(x,-y);}// Draw the two sides of the ellipse (second region)floatd2=SQUARE(y_radius*(x+0.5))+SQUARE(x_radius*(y-1))-x_radius_square*y_radius_square;while(y>0){if(d2<=0){// Next point is to the east of the current pointd2+=y_radius_square*(2*x+2)+x_radius_square*(-2*y+3);x++;}else{// Next point is southeast of the current pointd2+=x_radius_square*(-2*y+3);}y--;// Draw ellipse arc for each point on the sidesDRAW_OFFSET_POINT(x,y);DRAW_OFFSET_POINT(-x,-y);DRAW_OFFSET_POINT(-x,y);DRAW_OFFSET_POINT(x,-y);}if(CFBDGraphic_DeviceRequestUpdateAtOnce(handler)){int32_tlx=asInt32_t(ellipse->center.x)-x_radius;int32_tty=asInt32_t(ellipse->center.y)-y_radius;int32_trx=asInt32_t(ellipse->center.x)+x_radius;int32_tby=asInt32_t(ellipse->center.y)+y_radius;handler->ops->update_area(handler,clamp_u16_from_i32(lx),clamp_u16_from_i32(ty),clamp_u16_from_i32(rx-lx+1),clamp_u16_from_i32(by-ty+1));}}voidCFBDGraphic_DrawFilledEllipse(CFBD_GraphicDevice*handler,CFBD_GraphicEllipse*ellipse){PREANNOUNCE;CFBD_Bool(*setPixel)(CFBD_GraphicDevice*device,uint16_tx,uint16_ty)=handler->ops->setPixel;constint16_tx_radius=ellipse->X_Radius;constint16_ty_radius=ellipse->Y_Radius;clearBound(handler,ellipse,x_radius,y_radius);// Bresenham's Ellipse Algorithm to avoid costly floating point calculations// Reference: https://blog.csdn.net/myf_666/article/details/128167392int16_tx=0;int16_ty=y_radius;constint16_ty_radius_square=SQUARE(y_radius);constint16_tx_radius_square=SQUARE(x_radius);// Initial decision variable for the first region of the ellipsefloatd1=y_radius_square+x_radius_square*(-y_radius+0.5);// Fill the ellipse by drawing vertical lines in the specified range (filled area)for(int16_tj=-y;j<y;j++){// Draw vertical lines to fill the area of the ellipseDRAW_OFFSET_POINT(0,j);DRAW_OFFSET_POINT(0,j);}// Draw initial points on the ellipse (4 points due to symmetry)DRAW_OFFSET_POINT(x,y);DRAW_OFFSET_POINT(-x,-y);DRAW_OFFSET_POINT(-x,y);DRAW_OFFSET_POINT(x,-y);// Draw the middle part of the ellipse (first region)while(y_radius_square*(x+1)<x_radius_square*(y-0.5)){if(d1<=0){// Next point is to the east of the current pointd1+=y_radius_square*(2*x+3);}else{// Next point is southeast of the current pointd1+=y_radius_square*(2*x+3)+x_radius_square*(-2*y+2);y--;}x++;// Fill the ellipse by drawing vertical lines in the current rangefor(int16_tj=-y;j<y;j++){DRAW_OFFSET_POINT(x,j);DRAW_OFFSET_POINT(-x,j);}// Draw ellipse arc for each point in the current regionDRAW_OFFSET_POINT(x,y);DRAW_OFFSET_POINT(-x,-y);DRAW_OFFSET_POINT(-x,y);DRAW_OFFSET_POINT(x,-y);}// Draw the two sides of the ellipse (second region)floatd2=SQUARE(y_radius*(x+0.5))+SQUARE(x_radius*(y-1))-x_radius_square*y_radius_square;while(y>0){if(d2<=0){// Next point is to the east of the current pointd2+=y_radius_square*(2*x+2)+x_radius_square*(-2*y+3);x++;}else{// Next point is southeast of the current pointd2+=x_radius_square*(-2*y+3);}y--;// Fill the ellipse by drawing vertical lines in the current rangefor(int16_tj=-y;j<y;j++){DRAW_OFFSET_POINT(x,j);DRAW_OFFSET_POINT(-x,j);}// Draw ellipse arc for each point on the sidesDRAW_OFFSET_POINT(x,y);DRAW_OFFSET_POINT(-x,-y);DRAW_OFFSET_POINT(-x,y);DRAW_OFFSET_POINT(x,-y);}if(CFBDGraphic_DeviceRequestUpdateAtOnce(handler)){int32_tlx=asInt32_t(ellipse->center.x)-x_radius;int32_tty=asInt32_t(ellipse->center.y)-y_radius;int32_trx=asInt32_t(ellipse->center.x)+x_radius;int32_tby=asInt32_t(ellipse->center.y)+y_radius;handler->ops->update_area(handler,clamp_u16_from_i32(lx),clamp_u16_from_i32(ty),clamp_u16_from_i32(rx-lx+1),clamp_u16_from_i32(by-ty+1));}}#undef DRAW_OFFSET_POINT#undef SQUARE