public import "ecere" public enum CircleBorder { outsideBevel, insideBevel }; public enum CircleType { emptyCircle, fullCircle }; public struct Circle { CircleBorder borderType; borderType = outsideBevel; //Point center; int cX, cY; int radius; int borderSize; borderSize = 1; property int borderSize { get { return borderSize; } set { if(value < 1) { borderSize = 1; } else { borderSize = value; } } } property int leftMostPoint { get { return cX - radius; } } property int topMostPoint { get { return cY - radius; } } property int rightMostPoint { get { return cX + radius; } } property int bottomMostPoint { get { return cY + radius; } } public bool isPointInside(Point point, bool countOnBorder) { float gps; //it can be int (will function properly, but will give warning). int nrad; int rMin, rMax; nrad = radius * -1; //Some faster calculations to speed things up.. if( (point.y - cY) < nrad || (point.y - cY) > radius) { return false; } if((point.x-cX) < nrad || (point.x-cX) > radius) { return false; } gps = fastSqrt((point.x-cX)*(point.x-cX) + (point.y-cY)*(point.y-cY)); if(borderType == insideBevel) { rMin = radius - borderSize; rMax = radius; } else // borderType == outsideBevel { rMin = radius; rMax = radius + borderSize; } if(gps < radius) { //The point is inside of a circle return true; } else if(gps == radius || (gps > rMin && gps < rMax) ) { //The point is on the border if(countOnBorder) { return true; } } //Else - The point is not in the circle nor on the border (or the border is not included) return false; } //Other functions found in Box struct //----------------------------------------------------------------- //Check what these do for box and if applicable... void ClipOffset(Circle against, int x, int y) { } void Clip(Circle against) { } bool Overlap(Circle circle) { if( leftMostPoint < circle.rightMostPoint && rightMostPoint > circle.leftMostPoint && topMostPoint < circle.bottomMostPoint && bottomMostPoint > circle.topMostPoint) { //It is inside of the circle's `box` so it should be studied more carefully if it is // trully overlaping or not... float overlap; //it can be int (will function properly, but will give warning). int rad; float h, w; w = cX - circle.cX; h = cY - circle.cY; overlap = fastSqrt((w*w)+(h*h)); rad = radius + circle.radius; if(overlap < rad) { return true; } } return false; } }; private float fastSqrt(float x) { //http://www.codeproject.com/Articles/69941/Best-Square-Root-Method-Algorithm-Function-Precisi //Method number 1 union { int i; float x; } u; u.x = x; u.i = (1<<29) + (u.i >> 1) - (1<<22); // Two Babylonian Steps (simplified from:) // u.x = 0.5f * (u.x + x/u.x); // u.x = 0.5f * (u.x + x/u.x); u.x = u.x + x/u.x; u.x = 0.25f*u.x + x/u.x; return u.x; } void DrawCircle(Surface surface, Circle circle) { ColorAlpha color[2]; color[0] = black; color[1] = black; DrawCircleF(surface, circle.cX, circle.cY, circle.radius, emptyCircle, color, circle.borderSize, circle.borderType); } void DrawCircleF(Surface surface, int x0, int y0, int radius, CircleType circleType, ColorAlpha color[2], int borderSize, CircleBorder borderStyle ) { int f, fX, fY, x, y; f = 1 - radius; fX = 1; fY = -2 * radius; x = 0; y = radius; //Put the dot in the center of the circle //SetForeground(red); //PutPixel(x0,y0); //The border should always be drawn, not only if empty, as that way you can have // only line drawn, full color circle and colored circle with borders // this might not be wanted for circle if angles only //Draw borders surface.SetForeground(color[0]); surface.PutPixel(x0, y0 + radius); surface.PutPixel(x0, y0 - radius); //circle dots on the X axis on both sides of circle surface.PutPixel(x0 + radius, y0); surface.PutPixel(x0 - radius, y0); if(circleType == fullCircle) { surface.SetForeground(color[1]); surface.DrawLine(x0, y0 + radius, x0, y0 - radius); surface.DrawLine(x0 + radius, y0, x0 - radius+1, y0); } while(x < y) { // fX == 2 * x + 1; // fY == -2 * y; // f == x*x + y*y - radius*radius + 2*x - y + 1; if(f >= 0) { y--; fY += 2; f += fY; } x++; fX += 2; f += fX; //Draw other dots... each line representing one sector... if(circleType == emptyCircle) //only border is shown { surface.PutPixel(x0 + x, y0 + y); surface.PutPixel(x0 - x, y0 + y); surface.PutPixel(x0 + x, y0 - y); surface.PutPixel(x0 - x, y0 - y); surface.PutPixel(x0 + y, y0 + x); surface.PutPixel(x0 - y, y0 + x); surface.PutPixel(x0 + y, y0 - x); surface.PutPixel(x0 - y, y0 - x); } else if(circleType == fullCircle) //everything is filled up.. { surface.DrawLine(x0 + x, y0 + y, x0 - x, y0 + y); surface.DrawLine(x0 + x, y0 - y, x0 - x, y0 - y); surface.DrawLine(x0 + y, y0 + x, x0 - y, y0 + x); surface.DrawLine(x0 + y, y0 - x, x0 - y, y0 - x); } } if(borderSize > 1) { if(borderStyle == insideBevel) { DrawCircleF(surface, x0, y0, radius-1, circleType, color, borderSize-1, borderStyle ); } else { DrawCircleF(surface, x0, y0, radius+1, circleType, color, borderSize-1, borderStyle ); } } } class Form1 : Window { caption = "Form1"; background = formColor; borderStyle = sizable; hasMaximize = true; hasMinimize = true; hasClose = true; clientSize = { 632, 438 }; //Lets add few circles Circle c1 {borderSize = 1;borderType = outsideBevel; cX = 270; cY = 65; radius = 38; }; Circle c2 {borderSize = 1;borderType = outsideBevel; cX = 102; cY = 83; radius = 150; }; Circle c3 {borderSize = 1;borderType = outsideBevel; cX = 321; cY = 130; radius = 50; }; // The Clip() functions that work for the box are not done // The filled angles will be available at some other time, but the idea was to have the // possibility of pie chart if it was needed, but it should be based on angles and I have // some other idea in mind for that so will see what will happen - it might end up transferred to // some other class instead... void OnRedraw(Surface surface) { ColorAlpha colors[2]; ColorAlpha colors2[2]; colors[0] = black; //border color colors[1] = red; //background color colors2[0] = blue; colors2[1] = green; //Lets draw these circles DrawCircle(surface, c1); //A quick way to draw them, which does not give you a lot of // room to do anything with it //DrawCircleF(surface, x0,y0,radius,curcleType,color[2],borderSize,borderStyle); DrawCircleF(surface, c2.cX,c2.cY,c2.radius,fullCircle,colors,c2.borderSize,c2.borderType); DrawCircleF(surface, c3.cX,c3.cY,c3.radius,fullCircle,colors2,c3.borderSize,c3.borderType); } //Lets see what we can do with this... bool OnLeftButtonDown(int x, int y, Modifiers mods) { bool tc1, tc2, tc3; String msg; msg = "The click happened outside of any circle"; //default value tc1 = c1.isPointInside({x,y},true); // Sometimes you want the border to be considered as the // part of the circle, then you say true, but if you do not want // to have border included in the calculations then just put // false and it will not be counted tc2 = c2.isPointInside({x,y},false); tc3 = c3.isPointInside({x,y},true); if(tc1) { msg = "the 'c1' circle was hit"; } else if(tc2) { msg = "the 'c2' circle was hit"; } else if(tc3) { msg = "the 'c3' circle was hit"; } MessageBox {this, text = "results", contents = msg}.Modal(); return true; } bool OnRightButtonDown(int x, int y, Modifiers mods) { //Lets see if the circles are overlapping each other... if(c1.Overlap(c2)) { MessageBox {this, text = "results", contents = "c1 and c2 overlap"}.Modal(); } if(c1.Overlap(c3)) { MessageBox {this, text = "results", contents = "c1 and c3 overlap"}.Modal(); } if(c2.Overlap(c3)) { MessageBox {this, text = "results", contents = "c2 and c3 overlap"}.Modal(); } return true; } } class Form2 : Window { caption = "Form2"; background = formColor; borderStyle = sizable; hasMaximize = true; hasMinimize = true; hasClose = true; clientSize = { 632, 438 }; //Lets add few circles Circle c1 {borderSize = 1;borderType = outsideBevel; cX = 270; cY = 65; radius = 38; }; Circle c2 {borderSize = 1;borderType = outsideBevel; cX = 102; cY = 83; radius = 150; }; Circle c3 {borderSize = 1;borderType = outsideBevel; cX = 321; cY = 130; radius = 50; }; //Lets do something more with it.. bool c1Inside, c2Inside, c3Inside; c1Inside = false; c2Inside = false; c3Inside = false; // The Clip() functions that work for the box are not done // The filled angles will be available at some other time, but the idea was to have the // posibility of pie chart if it was needed, but it should be based on angles and I have // some other idea in mind for that so will see what will happen - it might end up transfered to // some other class instead... void OnRedraw(Surface surface) { ColorAlpha colors[2]; ColorAlpha colors2[2]; ColorAlpha colorsO[2]; ColorAlpha colors2O[2]; //Normal colors colors[0] = black; colors[1] = red; colors2[0] = blue; colors2[1] = green; //Over colorsO[0] = white; colorsO[1] = yellow; colors2O[0] = red; colors2O[1] = brown; //Lets draw these circles if(c1Inside) { DrawCircleF(surface, c1.cX,c1.cY,c1.radius,fullCircle,colorsO,c1.borderSize,c1.borderType); } else { DrawCircle(surface, c1); //A quick way to draw them, which does not give you a lot of // room to do anything with it } //surface.DrawCircleF(x0,y0,radius,curcleType,color[2],borderSize,borderStyle); if(c2Inside) { DrawCircleF(surface, c2.cX,c2.cY,c2.radius,fullCircle,colors2O,c2.borderSize,c2.borderType); } else { DrawCircleF(surface, c2.cX,c2.cY,c2.radius,fullCircle,colors,c2.borderSize,c2.borderType); } if(c3Inside) { DrawCircle(surface, c3); } else { DrawCircleF(surface, c3.cX,c3.cY,c3.radius,fullCircle,colors2,c3.borderSize,c3.borderType); } } //Lets see what we can do with this... bool OnMouseMove(int x, int y, Modifiers mods) { c1Inside = false; c2Inside = false; c3Inside = false; if(c1.isPointInside({x,y},true)) { c1Inside = true; } if(c2.isPointInside({x,y},true)) { c2Inside = true; } if(c3.isPointInside({x,y},true)) { c3Inside = true; } Update(null); return true; } bool OnLeftButtonDown(int x, int y, Modifiers mods) { bool tc1, tc2, tc3; String msg; msg = "The click happend outside of any circle"; //default value tc1 = c1.isPointInside({x,y},true); // Sometimes you want the border to be considered as the // part of the circle, then you say true, but if you do not want // to have border included in the calculations then just put // false and it will not be counted tc2 = c2.isPointInside({x,y},false); tc3 = c3.isPointInside({x,y},true); if(tc1) { msg = "the 'c1' circle was hit"; } else if(tc2) { msg = "the 'c2' circle was hit"; } else if(tc3) { msg = "the 'c3' circle was hit"; } MessageBox {this, text = "results", contents = msg}.Modal(); return true; } bool OnRightButtonDown(int x, int y, Modifiers mods) { //Lets see if the circles are overlapping each other... if(c1.Overlap(c2)) { MessageBox {this, text = "results", contents = "c1 and c2 overlap"}.Modal(); } if(c1.Overlap(c3)) { MessageBox {this, text = "results", contents = "c1 and c3 overlap"}.Modal(); } if(c2.Overlap(c3)) { MessageBox {this, text = "results", contents = "c2 and c3 overlap"}.Modal(); } return true; } } Form1 form1 {}; Form2 form2 {};