I'm trying to make a timer that mimics a clock, with a ticking hand. I have no problem drawing a clock texture and then a line for the hand, but I also want the space behind the clock hand to have a fill. So as time goes on, I want the clock to "fill up" starting at the origin (0:00) all the way up to the clock hand.
I basically want to do this:
What's the best way for me to do this? I have the foundation, just don't know how to add the fill part.
You should aproximate it building a triangle fan.
int n=0;
VertexPostionColor[] V = new VertexPositionColor[num_triangles+2]
V[0] = Center;
for (var angle = start ;angle<=end; angle += (end - start) / num_triangles)
{
V[++N].Position = new Vector3( Math.Cos(angle), Math.Sin(angle)) * radius + Center;
V[N].Color = CircleColor;
}
Short[] Index = new Short[num_triangles*3];
for (int i = 0; i< num_triangles; i++)
{
Index[i*3] = 0;
Index[i*3+1] = i+1;
Index[i*3+2] = i+2;
}
GraphicsDevice.DrawUserIndexedPrimitives(...);
If you want to get complicated using a spritebatch, you have to use a small sector texture, and draw it multiple times rotating it about the center.
this is an example, it need to be tuned to be precise.
float SectorAngle = Mathhelper.ToRadians(10);
Texture2D SectorTex;
Vector2 Origin = new Vector2(SectorTex.Width/2, SectorTex.Height);
for (var angle=start; angle<=end; angle+=SectorAngle) {
spriteBatch.Draw(SectorTex, Center, null, Color.White, Origin, angle, scale,...)
}
If you want to do it using textures, you should be able to manage it with two simple textures: a semi-circle (exactly half a circle), and a full circle.
First, draw the full circle white. Then it's just a matter of calculating how much of the circle needs to be filled.
If it's less than half, draw the half circle blue, rotated to match the "minute hand". Then draw another half circle white to cover the left side.
If it's more than half, draw the half circle blue, covering the entire right side. Then draw another half circle blue, rotated to match the "minute hand".
Once the fill is complete, you just need to draw the other clock components; the hands and border.
Related
I have an image with some text in 90 deg, which I'm reading using tesseract and c#. Since the accuracy of reading rotated text is low in tesseract I'm creating an ROI around the text and rotating the roi to make the ROI part of image straight and then reading it with tesseract.
To summarize - There is a main image, within the main image I'm drawing and ROI around the text >> then I'm rotating the ROI 90 degree to make it straight >> then I'm reading the text >> then I draw the bounding rect around each character.
But the bounding box that I get is drawn like it was a straight image and not the original 90 deg ROI. I need the bounding boxes to be drawn on the original ROI. How do I do that?
Here is how it looks :
Here is how I want it to look :
This is the code I use to draw rectangle around each character:
rotatedimg = mainimg.Clone();
for (int i = 0; i <roiincrement; i++)
{
rotatedimg.ROI = ROIRect[i];
rotatedimg.Rotate(90.0, new McvScalar(255,255,255); // rotating the image 0 deg to make it straight for tesseract to read
///....reading part of tesseract.
var page = tesseract.Process(rotatedimg, PageSegMode.Auto)
using (var iter = page.GetIterator()) //this parts draw the rect for each character
{
iter.Begin();
Rect symbolBounds;
do
{
if (iter.TryGetBoundingBox(PageIteratorLevel.Symbol, out symbolBounds))
{
CvInvoke.cvRectangle(resultimg, new System.Drawing.Point(ROIRect[i].X + symbolBounds.X1, ROIRect[i].Y + symbolBounds.Y1), new System.Drawing.Point(ROIRect[i].X + symbolBounds.X2, ROIRect[i].Y + symbolBounds.Y2), new MCvScalar(0, 255, 0), 1, LINE_TYPE.FOUR_CONNECTED, 0);
}
} while (iter.Next(PageIteratorLevel.Symbol));
}
}
Well I couldn't find any reasonable answers to this question so I took a shortcut. I simply took the ROI of the image before it is rotated for tesseract to read, then found the contours and draw rectangles around those contours. By doing this I get the required bounding boxes. It does add a couple of ms to the processing time, but not much.
This is the result I get now :
Before you point out that there are other answers to this question, i have looked at if not all, most of the other answers to this question or a similar question and i haven't found the solution i require.
Basically all i want to be able to do is when the circle/ball collides with a rectangle, i want to determine which side of the rectangle this collision has occured at. I want to find this out so that i can enforce a bit more realistic physics, e.g. if the ball hits the top of the rectangle, inverse it's Y velocity only... instead of both.
I have tried comparing the X and Y positions of the ball and the rectangle and even the location of both of their bounding boxes... testing even if the bottom of the ball's box has intersected with the rectangles top... using 'if ball.boundingBox.Bottom >= rectangle.boundingBox.Top'.
I have attached a picture to this to show what i am trying to achieve... just in case it's a bit confusing, as it's not detailed... the red what look like v's is the path if the ball comes in from one side, i want the movement upon impact to travel in the opposite way but this depends on the side of the rectangle as to what component of the ball's velocity i will have to change...
FYI i have also looked at vector normalisation... i haven't used it before so forgive me if this could be solved using this...
Thanks v.much for reading
EDIT as i am in a rush, i have used an different image instead... this still shows the behaviour i am trying to achieve, as the physics shown on the diagram is how i want the ball to behave when it collides with the other sides...
LINK TO IMAGE: http://codeincomplete.com/posts/2011/6/12/collision_detection_in_breakout/bounce2.v283.png
This code might be more comprehensive than you need and can be refactored to suit your needs but it is a complete answer and is flexible to use with moving bounding rectangles along with moving circles.
here is a graphic to give a visual aid to what the code is doing.
the red circle is intersecting with the black rectangle. visualize two imaginary lines going through opposite corners. If you know which side of each of the 2 lines the circle is on, you can deduce the collided edge.
first declare class scope private members
Rectangle CollisionBoxRect;
Rectangle circleRect;
Dictionary<string, Vector2> corners;
In your update after you've moved the circle and set its location and the potential intersected box's location it does a basic check to see if the circle's bounding rect is involved with the block's bounding rect. If so, it then alters the ball's velocity with the appropriate collision normal depending on which side of the rect the circle collided with.
if (CollisionBoxRect.Intersects(circleRect))
{
ballVelocity = Vector2.Reflect(ballVelocity, GetCollisionNormal(CollisionBoxRect));
}
The following methods support getting the proper side (the normal actually). Some of these methods can be done once in the initialize phase if they never change (like the get corners method);
private Vector2 GetCollisionNormal(Rectangle boxBeingIntersected)
{
getCorners(boxBeingIntersected);
bool isAboveAC = isOnUpperSideOfLine(corners["bottomRight"], corners["topLeft"], getBallCenter());
bool isAboveDB = isOnUpperSideOfLine( corners["topRight"], corners["bottomLeft"], getBallCenter());
if (isAboveAC)
{
if (isAboveDB)
{
//top edge has intersected
return -Vector2.UnitY;
}
else
{
//right edge intersected
return Vector2.UnitX;
}
}
else
{
if (isAboveDB)
{
//left edge has intersected
return -Vector2.UnitX;
}
else
{
//bottom edge intersected
return Vector2.UnitY;
}
}
}
public bool isOnUpperSideOfLine(Vector2 corner1, Vector2 oppositeCorner, Vector2 ballCenter)
{
return ((oppositeCorner.X - corner1.X) * (ballCenter.Y - corner1.Y) - (oppositeCorner.Y - corner1.Y) * (ballCenter.X - corner1.X)) > 0;
}
private Vector2 getBallCenter()
{
return new Vector2(circleRect.Location.X + circleRect.Width / 2, circleRect.Location.Y + circleRect.Height / 2);
}
private void getCorners(Rectangle boxToGetFrom)
{
corners.Clear();
Vector2 tl = new Vector2(boxToGetFrom.X, boxToGetFrom.Y);
Vector2 tr = new Vector2(boxToGetFrom.X + boxToGetFrom.Width, boxToGetFrom.Y);
Vector2 br = new Vector2(boxToGetFrom.X + boxToGetFrom.Width, boxToGetFrom.Y + boxToGetFrom.Height);
Vector2 bl = new Vector2(boxToGetFrom.X, boxToGetFrom.Y + boxToGetFrom.Height);
corners.Add("topLeft", tl);
corners.Add("topRight", tr);
corners.Add("bottomRight", br);
corners.Add("bottomLeft", bl);
}
I'm having a little trouble with a texture2d I'm trying to draw in XNA. Basically, I have a power-up "cooldown fill-effect" going on. I have a texture that I'm trying to draw partially as the cooldown decreases. So, for example, at 10% cooldown done I'm drawing only 10% cooldown of of the texture (the bottom), 20% done only 20% of the bottom of the texture, and so on.
The problem I'm having is, when drawing the texture, it keeps wobbling as it fills up.
Note that below, ActiveSkillTexture is my preloaded fill texture. It's size is the size of the fully filled graphic.
InterfaceDrawer.Draw is a method that calls SpriteBatch.Draw, but does some extra stuff beforehand. For all intents and purposes, it's the same as SpriteBatch.Draw.
Scale is my scale factor, it's just a float between 0 and 1.
MyDest is a pre-calculated position for where this texture should draw (from the top-left, as usual).
Here's a snippet of code:
Rectangle NewBounds = ActiveSkillTexture.Bounds;
float cooldown = GetCooldown(ActiveSkillId);
if (cooldown > 0) //cooldown timer
{
//Code that calculated cooldown percent which I'm leaving out
if (percentdone != 1) //the percentage the cooldown is done
{
//code for fill-from bottom --
float SubHeight = ActiveSkillTexture.Height * percentremaining;
float NewHeight = ActiveSkillTexture.Height * percentdone;
NewBounds.Y += (int) SubHeight;
NewBounds.Height = (int) NewHeight;
MyDest.Y += SubHeight * Scale;
}
}
if (ActiveSkillTexture != null)
InterfaceDrawer.Draw(SpriteBatch, ActiveSkillTexture, MyDest, NewBounds, Color, 0.0f, Vector2.Zero, Scale, SpriteEffects.None, 0.0f);
I know you can't see it, but it's basically wobbling up and done as it fills. I tried printing out the values for the destination, the newbounds rectangle, etc. and they all seemed to consistently increase and not "sway", so I'm not sure what's going on. Interestingly enough, if I fill it from the top, it doesn't happen. But that's probably because I don't have to do math to alter the destination position each time I draw it (because it should draw from the top-left corner each time).
Any help would be greatly appreciated. Thanks!
I think this would be easier if you set the Vector2.Origin parameter of your spriteBatch.Draw as the bottom-left of your texture.
In this way you simply increase your sourceRectangle.Height, with something like this:
sourceRectangle.Height = ActiveSkillTexture.Height * percentdone;
without doing that useless math to find the destination position.
I'm trying to detect rectangles on this image:
with this code:
static void Main(string[] args)
{
// Open your image
string path = "test.png";
Bitmap image = (Bitmap)Bitmap.FromFile(path);
// locating objects
BlobCounter blobCounter = new BlobCounter();
blobCounter.FilterBlobs = true;
blobCounter.MinHeight = 5;
blobCounter.MinWidth = 5;
blobCounter.ProcessImage(image);
Blob[] blobs = blobCounter.GetObjectsInformation();
// check for rectangles
SimpleShapeChecker shapeChecker = new SimpleShapeChecker();
foreach (var blob in blobs)
{
List<IntPoint> edgePoints = blobCounter.GetBlobsEdgePoints(blob);
List<IntPoint> cornerPoints;
// use the shape checker to extract the corner points
if (shapeChecker.IsQuadrilateral(edgePoints, out cornerPoints))
{
// only do things if the corners form a rectangle
if (shapeChecker.CheckPolygonSubType(cornerPoints) == PolygonSubType.Rectangle)
{
// here i use the graphics class to draw an overlay, but you
// could also just use the cornerPoints list to calculate your
// x, y, width, height values.
List<Point> Points = new List<Point>();
foreach (var point in cornerPoints)
{
Points.Add(new Point(point.X, point.Y));
}
Graphics g = Graphics.FromImage(image);
g.DrawPolygon(new Pen(Color.Red, 5.0f), Points.ToArray());
image.Save("result.png");
}
}
}
}
but it dont recognize the rectangles (walls). It just recognize the big square, and when I reduce the minHeight and minWidth, it recognize trapezoids on the writing..
I propose a different algorithm approach, after working almost a year with image processing algorithms what I can tell is that to create an efficient algorithm, you have to "reflect" how you, as a human would do that, here is the proposed approach:
We don't really care about the textures, we care about the edges (rectangles are edges), therefore we will apply an Edge-detection>Difference (http://www.aforgenet.com/framework/docs/html/d0eb5827-33e6-c8bb-8a62-d6dd3634b0c9.htm), this gives us:
We want to exaggerate the walls, as humans we know that we are looking for the walls, but the computer does not know this, therefore, apply two rounds of Morphology>Dilatation (http://www.aforgenet.com/framework/docs/html/88f713d4-a469-30d2-dc57-5ceb33210723.htm), this gives us:
We care only about the what is wall and what is not, apply a Binarization>Threshold (http://www.aforgenet.com/framework/docs/html/503a43b9-d98b-a19f-b74e-44767916ad65.htm), we get:
(Optional) We can apply a blob extraction to erase the labels ("QUARTO, BANHEIRO", etc)
We apply a Color>Invert, this is just done because the next step detects the white color not black.
Apply a Blob>Processing>Connected Components Labeling (http://www.aforgenet.com/framework/docs/html/240525ea-c114-8b0a-f294-508aae3e95eb.htm), this will give us all the rectangles, like this:
Note that for each colored box you have its coordinates, center, width and height. So you can extract a snip from the real image with that coordinates.
PS: Using the program AForge Image Processing Lab is highly recommended to test your algos.
Each time a rectangle is found, the polygon is drawn on Graphics and the file is saved only for THAT rectangle. This means that result.png will only contain a single rectangle at a time.
Try first saving all the rectangles in a List<List<Points>> and then going over it and add ALL the rectangles to the image. Something like this (Pseudo):
var image..
var rectangles..
var blobs..
foreach (blob in blobs)
{
if (blob is rectangle)
{
rectangles.add(blob);
}
}
foreach (r in rectangles)
{
image.draw(r.points);
}
image.save("result.png");
If your problem now is to avoid noise due to writings on the image, use FillHoles with widht and height of holes smaller than the smallest rectangle but larger than any of the writings.
If the quality of image is good and no text is touching the border of the image, Invert the image and FillHoles will remove most of the stuff.
Hope I understood your problem correctly.
We are trying to detect rectangles in so many rectangles (considering gray rectangles of grid). Almost all algorithms will get confused here. You're not eliminating externals from input image. Why not replace grid line color with background color or use threshold above to eliminate all grids first.
Then grow all pixels equal to the width of wall, Find all horizontal and vertical lines thereafter use maths to find rectangles using detected lines. Uncontrolled filling will be risky as when boundries are not closed fill will make two rooms as one rectangle.
I am working on a simple game where you click on square sprites before they disappear. I decided to get fancy and make the squares rotate. Now, when I click on the squares, they don't always respond to the click. I think that I need to rotate the click position around the center of the rectangle(square) but I am not sure how to do this. Here is my code for the mouse click:
if ((mouse.LeftButton == ButtonState.Pressed) &&
(currentSquare.Contains(mouse.X , mouse.Y )))
And here is the rotation logic:
float elapsed = (float)gameTime.ElapsedGameTime.TotalSeconds;
RotationAngle += elapsed;
float circle = MathHelper.Pi * 2;
RotationAngle = RotationAngle % circle;
I am new to Xna and programming in general, so any help is appreciated.
Thanks a lot,
Bill
So you're trying to determine if a point is in a rectangle, but when the rectangle is rotated?
The Contains() method will only work if the current rotation is 0 (I guess currentSquare is a rectangle representing the image position without rotation?).
What you will have to do is do the opposite rotation of the image on the mouse coordinates (the mouse coordinates should rotate around the origin of your image), then calculate if the new position is within currentSquare. You should be able to do all of this using vectors.
(Untested)
bool MouseWithinRotatedRectangle(Rectangle area, Vector2 tmp_mousePosition, float angleRotation)
{
Vector2 mousePosition = tmp_mousePosition - currentSquare.Origin;
float mouseOriginalAngle = (float)Math.Atan(mousePosition.Y / mousePosition.X);
mousePosition = new Vector2((float)(Math.Cos(-angleRotation + mouseOriginalAngle) * mousePosition.Length()),
(float)(Math.Sin(-angleRotation + mouseOriginalAngle) * , mousePosition.Length()));
return area.Contains(mousePosition);
}
If you dont need pixel pefect detection you can create bounding sphere for each piece like this.
var PieceSphere = new BoundingSphere()
{
Center =new Vector3(new Vector2(Position.X + Width/2, Position.Y + Height/2), 0f),
Radius = Width / 2
};
Then create another bounding sphere around mouse pointer.For position use mouse coordinates and for radius 1f. Because mouse pointer will be moving it will change its coordinates so you have to also update the sphere's center on each update.
Checking for clicks would be realy simple then.
foreach( Piece p in AllPieces )
{
if ((mouse.LeftButton == ButtonState.Pressed) && p.BoundingSphere.Intersects(MouseBoundingSphere))
{
//Do stuff
}
}
If you are lazy like me you could just do a circular distance check.
Assuming mouse and box.center are Vector2
#gets us C^2 according to the pythagorean Theorem
var radius = (box.width / 2).squared() + (box.height / 2).square
#distance check
(mouse - box.center).LengthSquared() < radius
Not perfectly accurate but the user would have a hard time noticing and inaccuracies that leave a hitbox slightly too large are always forgiven. Not to mention the check is incredibly fast just calculate the radius when the square is created.