Calculating the area(s) of a rectangle that aren't being overlapped - math

I've got two rectangles represented by structures that contain the x1, y1, x2, y2 coordinates. One rectangle can be considered the parent, another the child.
I already know how to detect if the child rectangle is within the parent rectangle; what I'm trying to figure out now is the simplest, fastest way to determine the rectangular areas within the parent that are not being overlapped by the child rectangle.
For example, consider a 100x100 parent rectangle, and a 50x50 child rectangle located exactly in the center of the parent. This would mean there would be four rectangles representing the four areas in the parent rectangle that aren't being overlapped by the child.
Of course, the child could be in the top left, top right, bottom left, bottom right corner, or a little to the left, a little to the right, etc... there might be one, two, three, or four rectangles that represent the non-overlapped areas.
I've had some ideas for implementations to figure this out, but all seem overly complex. Is there a simple, fast way to figure this out?

So there could be up to 4 rectangles of non-overlapped area. Let's make a list of them.
leftrect = rightrect = toprect = bottomrect = None
trimmedparent = duplicate(parent)
if parent.x1 < child.x1:
leftrect = duplicate(parent)
leftrect.x2 = child.x1
trimmedparent.x1 = child.x1
if parent.x2 > child.x2:
rightrect = duplicate(parent)
rightrect.x1 = child.x2
trimmedparent.x2 = child.x2
if parent.y1 < child.y1:
toprect = duplicate(trimmedparent)
toprect.y2 = child.y1
if parent.y2 > child.y2:
bottomrect = duplicate(trimmedparent)
bottomrect.y1 = child.y2
The only tricky part is eliminating the part where e.g leftrect and toprect might intersect. I used 'trimmedparent' as an intermediate step to trim that section from toprect.

parent = Rectangle.new(x1,y1,mx1,my1)
child = Rectangle.new(x2,y2,mx2,my2)
rects = []
if (parent.contains(child))
rects.push Rectangle.new(parent.x, parent.y, parent.mx, child.y) if child.y>parent.y
rects.push Rectangle.new(parent.x, child.my, parent.mx, parent.my) if child.my<parent.my
rects.push Rectangle.new(parent.x, parent.y, child.x, pareny.my) if child.x>parent.x
rects.push Rectangle.new(child.mx, parent.y, parent.mx, parent.my) if child.mx<parent.mx
end

This is the basic algorithm:
For each point in the child, if it is inside the parent, the corresponding child and parent point form the diagonal a rectangle. Now, for each side of the child, if the two points are in the parent, those two points and the matching points on the edge of the parent form a rectangle. If only one of the points on the edge of the child is in the parent, this point and the parent point corresponding to the child edge point not in the parent form the diagonal for a rectangle. Return these rectangles.
You would get a maximum of eight rectangles (one for each corner, one for each edge). If you want the minimum possible rectangles, see if they share edges, and if they do, combine them.

Here's another way to calculate the non-overlapped area of the parent:
Function max(ByVal v1 As Double, ByVal v2 As Double) As Double
If v1 > v2 Then
Return v1
Else
Return v2
End If
End Function
Function min(ByVal v1 As Double, ByVal v2 As Double) As Double
If v1 > v2 Then
Return v2
Else
Return v1
End If
End Function
Function IntervalOverLap(ByVal p1 As Double, ByVal p2 As Double, ByVal c1 As Double, ByVal c2 As Double) As Double
'determine how much of the parent(p1 to p2) segment '
' is overlapped by the child(c1 to c2) segment '
'sort to standard direction '
Dim ph As Double = max(p1, p2)
Dim pl As Double = min(p1, p2)
Dim ch As Double = max(c1, c2)
Dim cl As Double = min(c1, c2)
'restrict the child to within the parent '
ch = min(ph, max(pl, ch))
cl = max(pl, min(cl, ph))
'return the overlapped length '
Return (ch - cl)
End Function
Function NonOverLappedArea(ByVal parent As Rectangle, ByVal child As Rectangle) As Double
'return the area of the parent '
' that is not overlapped by the child '
Return IntervalOverLap(parent.X1, parent.X2, child.X1, child.X2) _
* IntervalOverLap(parent.Y1, parent.Y2, child.Y1, child.Y2)
End Function

From your description, the child is always wholly contained by the parent. So the non-overlapping area is always going to be a rectangular donut, although it could be degenerate on any of the 4 sides since, a child edge could abut a parent edge, the fully degenerate case being the child is the same as the parent.
The donut can be decomposed into 4 rectangles. The decomposition may not be unique, meaning you could get different rectangles depending on how you perform the decomposition.
Of the 4 rectangles, discard the degenerate ones (those with 0 area) and you're done.
Here's a vertically biased decomposition
// assume the child is known to be in the parent bounds at this point
// assume parent and child are normalized
std::vector<CRect> rects;
CRect rect( parent.x1(), parent.y1(), child.x1(), parent.y2() ); // left
if ( rect.area() > 0.0 ) rects.push_back(rect);
rect.set( child.x1(), parent.y1(), child.x2(), child.y1() ); // bottom
if ( rect.area() > 0.0 ) rects.push_back(rect);
rect.set( child.x1(), child.y2(), child.x2(), parent.y2() ) ); // top
if ( rect.area() > 0.0 ) rects.push_back(rect);
rect.set( child.x2(), parent.y1(), parent.x2(), parent.y2() ) ); // right
if ( rect.area() > 0.0 ) rects.push_back(rect);
// yes, this could be written without all the code replication... :)

Related

Rendering 2d function plot

My task is to produce the plot of a 2-dimensional function in real time using nothing but linear algebra and color (imagine having to compute an image buffer in plain C++ from a function definition, for example f(x,y) = x^2 + y^2). The output should be something like this 3d plot.
So far I have tried 3 approaches:
1: Ray tracing:
Divide the (x,y) plane into triangles, find the z-values of each vertex, thus divide the plot into triangles. Intersect each ray with the triangles.
2: Sphere tracing:
a method for rendering implicit surfaces described here.
3: Rasterization:
The inverse of (1). Split the plot into triangles, project them onto the camera plane, loop over the pixels of the canvas and for each one choose the "closest" projected pixel.
All of these are way to slow. Part of my assignment is moving around the camera, so the plot has to be re-rendered in each frame. Please point me towards another source of information/another algorithm/any kind of help. Thank you.
EDIT
As pointed out, here is the pseudocode for my very basic rasterizer. I am aware that this code might not be flawless, but it should resemble the general idea. However, when splitting my plot into 200 triangles (which I do not expect to be enough) it already runs very slowly, even without rendering anything. I am not even using a depth buffer for visibility. I just wanted to test the speed by setting up a frame buffer as follows:
NOTE: In the JavaScript framework I am using, _ denotes array indexing and a..b composes a list from a to b.
/*
* Raster setup.
* The raster is a pxH x pxW array.
* Raster coordinates might be negative or larger than the array dimensions.
* When rendering (i.e. filling the array) positions outside the visible raster will not be filled (i.e. colored).
*/
pxW := Width of the screen in pixels.
pxH := Height of the screen in pixels.
T := Transformation matrix of homogeneous world points to raster space.
// Buffer setup.
colBuffer = apply(1..pxW, apply(1..pxH, 0)); // pxH x pxW array of black pixels.
// Positive/0 if the point is on the right side of the line (V1,V2)/exactly on the line.
// p2D := point to test.
// V1, V2 := two vertices of the triangle.
edgeFunction(p2D, V1, V2) := (
det([p2D-V1, V2-V1]);
);
fillBuffer(V0, V1, V2) := (
// Dehomogenize.
hV0 = V0/(V0_3);
hV1 = V1/(V1_3);
hV2 = V2/(V2_3);
// Find boundaries of the triangle in raster space.
xMin = min(hV0.x, hV1.x, hV2.x);
xMax = max(hV0.x, hV1.x, hV2.x);
yMin = min(hV0.y, hV1.y, hV2.y);
yMax = max(hV0.y, hV1.y, hV2.y);
xMin = floor(if(xMin >= 0, xMin, 0));
xMax = ceil(if(xMax < pxW, xMax, pxW));
yMin = floor(if(yMin >= 0, yMin, 0));
yMax = ceil(if(yMax < pxH, yMax, pxH));
// Check for all points "close to" the triangle in raster space whether they lie inside it.
forall(xMin..xMax, x, forall(yMin..yMax, y, (
p2D = (x,y);
i = edgeFunction(p2D, hV0.xy, hV1.xy) * edgeFunction(p2D, hV1.xy, hV2.xy) * edgeFunction(p2D, hV2.xy, hV0.xy);
if (i > 0, colBuffer_y_x = 1); // Fill all points inside the triangle with some placeholder.
)));
);
mapTrianglesToScreen() := (
tvRaster = homogVerts * T; // Triangle vertices in raster space.
forall(1..(length(tvRaster)/3), i, (
actualI = i / 3 + 1;
fillBuffer(tvRaster_actualI, tvRaster_(actualI + 1), tvRaster_(actualI + 2));
));
);
// After all this, render the colBuffer.
What is wrong about this approach? Why is it so slow?
Thank you.
I would go with #3 it is really not that complex so you should obtain > 20 fps on standard machine with pure SW rasterizer (without any libs) if coded properly. My bet is you are using some slow API like PutPixel or SetPixel or doing some crazy thing. Without seeing code or better description of how you do it is hard to elaborate. All the info you need to do this is in here:
Algorithm to fill triangle
HSV histogram
Understanding 4x4 homogenous transform matrices
Do look also in the sub-links in each ...

Drawing ECG in VB6.0

Whether is it possible to draw ECG in VB6.0? As i am not that much familiar with VB any type of help will be appreciated.Please help me .thanks in advance.
The simplest method to do this is to use a picture box with the AutoRedraw property set to true and the ScaleMode set to vbPixels.
For each point, you calculate the Y value (dependant on the minimum and maximum allowable values). To make it scan, just increment the X value for each point you draw wrapping back to 0 when it gets to the width of the picture box (.ScaleWidth).
You can use the picture box's .Line method to blank the areas behind the current X point and the .PSet method to draw the new point.
Dim X As Long
Dim LastValue As Long
Private Sub AddPoint(ByVal Value As Long)
'Clear the line behind (for 5 pixels forward)
Picture1.Line (X, 0)-(X + 5, Picture1.ScaleHeight), vbBlack, BF
'Draw the new point and the line from the previous point
Picture1.Line (X - 1, LastValue)-(X, Value), vbGreen
Picture1.PSet (X, Value), vbGreen
'Update the last value so we can draw the line between them
LastValue = Value
'Increment the X value for the next point
X = X + 1
If X = Picture1.ScaleWidth Then X = 0
End Sub
A better method is to use an off screen picture that you update using a similar method and just update the picturebox when needed.

Filling a grid with boxes with numbers with decreasing size

There is this interesting game, that has numbers in a grid, where each number has progressively smaller font. The player's task is to click on the numbers in succession.
I'm interested in the algorithm that creates the boxes for the numbers, I cannot think of a way it works.
Apparently the grid has N numbers (apart from the 1.88 in the picture), number 1 has the biggest font and succesively the font size decreases. Then the numbers are somehow placed on the grid and boxes grow around them. But it doesn't seem totally random, as there are some horizotal lines that go across the whole grid.
Do you have an idea on how this might work?
It looks to me as though the boxes have been generated by successive division. That is, starting with the full rectangle, a dividing line (horizontal or vertical) was placed, and then the two resulting rectangles were subdivided in turn, until there were enough rectangles for the game.
Here's a sketch of the first algorithm I would try. N is the number of rectangles I want to divide the original rectangle into, and A is a critical aspect ratio used to stop the small rectangles getting too narrow. (Perhaps A = 1.5 would be a good start.)
Create an empty priority queue and add the full rectangle to it.
If the length of the priority queue is greater than or equal to N, stop.
Remove the largest rectangle, R, from the priority queue.
Choose whether to divide it horizontally or vertically: if its aspect ratio (width/height) is greater than A, divide it vertically; if less than 1/A, divide it horizontally, otherwise choose at random.
Decide where to put the dividing line. (Perhaps randomly between 40% and 60% along the chosen dimension.)
This divides R into two smaller rectangles. Add both of them to the priority queue. Go to step 2.
When this algorithm completes, there are N rectangles in the queue. Put the number 1 in the largest of them, the number 2 in the second largest, and so on.
It turns out that putting the numbers into the boxes is not quite as straightforward as I assumed in my first attempt. The area metric works well for subdividing the rectangles nicely, but it doesn't work for putting the numbers into the boxes, because for fitting text into a box, the height and width both have to be taken into account (the area is not so useful).
Instead of explaining the algorithm for putting numbers into the boxes, I will just give you some sample code in Python and let you reverse-engineer it!
import heapq, itertools, random
import Image, ImageDraw, ImageFont
# ALGORITHM PARAMETERS
aspect_max = 1.5 # Above this ratio, always divide vertically
aspect_min = 1.0 # Below this ratio, always divide horizontally
div_min = 0.4 # Minimum position for dividing line
div_max = 0.6 # Maximum position for dividing line
digit_ratio = 0.7 # Aspect ratio of widest digit in font
label_margin = 2 # Margin around label (pixels)
class Rectangle(object):
def __init__(self, x, y, w, h):
self.x = x
self.y = y
self.w = w
self.h = h
self.area = self.w * self.h
self.aspect = float(self.w) / self.h
def __le__(self, other):
# The sense of this comparison is inverted so we can put
# Rectangles into a min-heap and be able to pop the largest.
return other.area <= self.area
def __repr__(self):
return 'Rectangle({0.x}, {0.y}, {0.w}, {0.h})'.format(self)
def divide(self, n):
"""
Divide this rectangle into `n` smaller rectangles and yield
them in order by area (largest first).
"""
def division(l):
return random.randrange(int(l * div_min), int(l * div_max))
queue = [self]
while len(queue) < n:
r = heapq.heappop(queue)
if (r.aspect > aspect_max
or r.aspect > aspect_min
and random.random() < 0.5):
# Vertical division
w = division(r.w)
heapq.heappush(queue, Rectangle(r.x, r.y, w, r.h))
heapq.heappush(queue, Rectangle(r.x + w, r.y, r.w - w, r.h))
else:
# Horizontal division
h = division(r.h)
heapq.heappush(queue, Rectangle(r.x, r.y, r.w, h))
heapq.heappush(queue, Rectangle(r.x, r.y + h, r.w, r.h - h))
while queue:
yield heapq.heappop(queue)
def font_height(self, n):
"""
Return the largest font height such that we can draw `n`
digits in this rectangle.
"""
return min(int((self.w - label_margin * 2) / (digit_ratio * n)),
self.h - label_margin * 2)
def draw_rectangles(rectangles, fontfile):
"""
Create and return an Image containing `rectangles`. Label each
rectangle with a number using the TrueType font in `fontfile`.
"""
rectangles = list(rectangles)
im = Image.new('RGBA', (1 + max(r.x + r.w for r in rectangles),
1 + max(r.y + r.h for r in rectangles)))
draw = ImageDraw.Draw(im)
for digits in itertools.count(1):
rectangles = sorted(rectangles,
key = lambda r: r.font_height(digits),
reverse = True)
i_min = 10 ** (digits - 1)
i_max = 10 ** digits
i_range = i_max - i_min
for i in xrange(i_range):
if i >= len(rectangles): return im
r = rectangles[i]
draw.line((r.x, r.y, r.x + r.w, r.y, r.x + r.w, r.y + r.h,
r.x, r.y + r.h, r.x, r.y),
fill = 'black', width = 1)
label = str(i + i_min)
font = ImageFont.truetype(fontfile, r.font_height(digits))
lw, lh = font.getsize(label)
draw.text((r.x + (r.w - lw) // 2, r.y + (r.h - lh) // 2),
label, fill = 'black', font = font)
rectangles = rectangles[i_range:]
Here's a sample run:
>>> R = Rectangle(0, 0, 400, 400)
>>> draw_rectangles(R.divide(30), '/Library/Fonts/Verdana.ttf').save('q10009528.png')
The pattern of the cuts looks recursive. That is, the process of dividing the region into rectangles consists of cutting a rectangle in two, over and over. There are two cuts that divide the whole rectangular region (the horizontal cuts above and below 1), so we can't tell which cut came first, but we see the cuts as a kind of tree: the cut that separates 1 from 10 produced a large rectangle below it (20, 21, 4, 10, etc.), which was then divided by the vertical cut between 21 and 4, the rectangle containing 4 was later divided by the cut that separates 4 and 14, and so on. There are N cuts that produce N regions plus one leftover ("1.88") which is not necessary but which might give us a clue.
Now we just have to figure out the order of the cuts, the choice of proportion and the choice of orientation.
Consecutive numbers are rarely neighbors, so it looks as if numbers are not assigned as the cutting progresses. Instead, the region is chopped into rectangles, the rectangles are sorted by size and then numbers are assigned (notice that 20 and 21 are neighbors, but they were formed by other cuts after the one that divides them).
A plausible hypothesis for the order of the cuts is that the algorithm always cuts the largest rectangle. If that were not true, we might see, e.g., 14 bigger than 15 and 18 combined, and I see no example of that.
Proportion... With careful measurement we could see the actual distribution of proportions, but I don't feel like doing that much work. We see no very long, thin rectangles and no 50/50 cuts, so at a guess I'd say the algorithm chooses randomly, in some range like [0.6, 0.8]. Maybe it tries to avoid making a rectangle very close to the size of a rectangle that already exists. After all the cuts, the rectangle chosen to be left over ("1.88") is neither the biggest nor the smallest; maybe it's random, maybe it's the second-biggest, maybe it's something else-- more examples would be useful.
The orientation seems to be strongly biased towards cutting rectangles across their narrow width, rather than "lengthwise". This has the effect of producing rectangles more like squares and less like books on a shelf. The only possible exception I can see is the 1-9 cut, which might divide the block whose lower-right number is 1 lengthwise. But that depends on the order of cuts above and below 1, so it leads to a hypothesis: the algorithm always cuts a rectangle along its shorter dimension, and the 1-9 cut was actually the first.
That's about as far as I can go, short of breaking out a ruler and calculator.

Finding Whether A Point is Within a Right-Angle Triangle

I've always wondered the easiest way to figure out whether or not a point lies within a triangle, or in this instance, a rectangle cut into half diagonally.
Let's say I have a rectangle that is 64x64 pixels. With this rectangle, I want to return a TRUE value if a passed point is within the upper-left corner of the rectangle, and FALSE if it isn't.
-----
| /|
| / |
|<__|
Horray for bad ASCII art.
Anyway, the hypothetical points for this triangle that would return TRUE would be (0,0) and (63,0) and (0, 63). If a point lands on a line (e.g., 50,0) it would return TRUE as well.
Assuming 0,0 is in the upper-left corner and increases downwards...
I've had a possible solution in my head, but it seems more complicated than it should be - taking the passed Y value, determining where it would be in the rectangle, and figuring out manually where the line would cut at that Y value. E.g, a passed Y value of 16 would be quarter height of the rectangle. And thus, depending on what side you were checking (left or right), the line would either be at 16px or 48px, depending on the direction of the line. In the example above, since we're testing the upper-left corner, at 16px height, the line would be at 48px width
There has to be a better way.
EDIT:
The rectangle could also look like this as well
-----
|\ |
| \ |
|__>|
But I'm figuring in most cases the current answers already provided should still hold up...
Top-left/bottom-right triangles: For all points in the top-left triangle, x+y<=64. Points in the bottom-right triangle have x+y>64.
(for a rectangle of size (w,h) use w*y+h*x-w*h<0)
Top-right/bottom-left triangles: For all points in the bottom-left triangle, x<=y. Points in the top-right triangle have x>y.
(for a rectangle of size (w,h) use h*x-w*y<0)
How did we get there?
For a rectangle of dimensions (w,h) and TL/BR triangles, the equation of the diagonal is (try it out! assign x=0 and check that you get y==h, and assign y=0 and check that x==w)
h*x + w*y - w*h = 0
Points on one side of that line will have
h*x + w*y - w*h > 0
While points on the other will have
h*x + w*y - w*h < 0
Inserting 64 for both w and h, we get:
64x + 64y - 64*64 < 0
Dividing by 64 gets us:
x+y < 64
For TR/BL triangles, the line equation and the resulting inequalities are:
h*x - w*y = 0
h*x - w*y < 0
h*x - w*y > 0
Inserting 64 for w and h, we get
64x-64y < 0
=> x<y
you can represent the triangle with three affine functions
take the unit triangle with corners at (0, 0), (1, 0) and (1, 1). the sides are represented by the three lines
y = 0
x = 1
y = x
So the interior and boundry of the triangle are given as the intersection of the sets
x >= 1
y >= 0
y <= x
so given a point, (x, y), you just need to verify that it satisfies those three inequalities.
You can of course generalize this to any triangle using the fact that any affine function (representing a line) can be written in the form y = mx + b.
The equation for the line looks like this :
y = mx + b
So, if you insert your x and y-Values into that equation, it will probably not hold anymore. Let's reformulate it:
mx + b - y = 0
Same thing, different look. Again, the result is probably not zero. But, the result will now tell you whether it's on the one side of the line or the other.
Now you just have to find out whether the point is inside your rectangle.
Lets assume your right angled triangle has one corner at 0,0 and the diagonal corner at a,b.
So y=mx+c c=0 as we start at the origin.
m=b/a
So y=bx/a
To know which half of the triangle your point (c,d) falls in
if (d<=(bc/a)) {//point is in bottom half}
if (d>(bc/a)) {//point is in top half}
I think...
A simple option is to use a ray casting algorithm. Whilst perhaps a little overkill for what you need, it does have the advantage that it will work with more complex triangles and polygons.
Loosely, the algorithm takes an imaginary point in a direction (infinitely off to the left, for example) and casts a ray to your test point; you then calculate whether each line of your triangle crosses that infinitely long line. If you get an odd number of crossings, your point is inside your triangle; even and you're out of your triangle

Given an angle and dimensions, find a coordinate along the perimeter of a rectangle

I'm writing a script where icons rotate around a given pivot (or origin). I've been able to make this work for rotating the icons around an ellipse but I also want to have them move around the perimeter of a rectangle of a certain width, height and origin.
I'm doing it this way because my current code stores all the coords in an array with each angle integer as the key, and reusing this code would be much easier to work with.
If someone could give me an example of a 100x150 rectangle, that would be great.
EDIT: to clarify, by rotating around I mean moving around the perimeter (or orbiting) of a shape.
You know the size of the rectangle and you need to split up the whole angle interval into four different, so you know if a ray from the center of the rectangle intersects right, top, left or bottom of the rectangle.
If the angle is: -atan(d/w) < alfa < atan(d/w) the ray intersects the right side of the rectangle. Then since you know that the x-displacement from the center of the rectangle to the right side is d/2, the displacement dy divided by d/2 is tan(alfa), so
dy = d/2 * tan(alfa)
You would handle this similarily with the other three angle intervals.
Ok, here goes. You have a rect with width w and depth d. In the middle you have the center point, cp. I assume you want to calculate P, for different values of the angle alfa.
I divided the rectangle in four different areas, or angle intervals (1 to 4). The interval I mentioned above is the first one to the right. I hope this makes sense to you.
First you need to calculate the angle intervals, these are determined completely by w and d. Depending on what value alfa has, calculate P accordingly, i.e. if the "ray" from CP to P intersects the upper, lower, right or left sides of the rectangle.
Cheers
This was made for and verified to work on the Pebble smartwatch, but modified to be pseudocode:
struct GPoint {
int x;
int y;
}
// Return point on rectangle edge. Rectangle is centered on (0,0) and has a width of w and height of h
GPoint getPointOnRect(int angle, int w, int h) {
var sine = sin(angle), cosine = cos(angle); // Calculate once and store, to make quicker and cleaner
var dy = sin>0 ? h/2 : h/-2; // Distance to top or bottom edge (from center)
var dx = cos>0 ? w/2 : w/-2; // Distance to left or right edge (from center)
if(abs(dx*sine) < abs(dy*cosine)) { // if (distance to vertical line) < (distance to horizontal line)
dy = (dx * sine) / cosine; // calculate distance to vertical line
} else { // else: (distance to top or bottom edge) < (distance to left or right edge)
dx = (dy * cosine) / sine; // move to top or bottom line
}
return GPoint(dx, dy); // Return point on rectangle edge
}
Use:
rectangle_width = 100;
rectangle_height = 150;
rectangle_center_x = 300;
rectangle_center_y = 300;
draw_rect(rectangle_center_x - (rectangle_width/2), rectangle_center_y - (rectangle_center_h/2), rectangle_width, rectangle_height);
GPoint point = getPointOnRect(angle, rectangle_width, rectangle_height);
point.x += rectangle_center_x;
point.y += rectangle_center_y;
draw_line(rectangle_center_x, rectangle_center_y, point.x, point.y);
One simple way to do this using an angle as a parameter is to simply clip the X and Y values using the bounds of the rectangle. In other words, calculate position as though the icon will rotate around a circular or elliptical path, then apply this:
(Assuming axis-aligned rectangle centered at (0,0), with X-axis length of XAxis and Y-axis length of YAxis):
if (X > XAxis/2)
X = XAxis/2;
if (X < 0 - XAxis/2)
X = 0 - XAxis/2;
if (Y > YAxis/2)
Y = YAxis/2;
if (Y < 0 - YAxis/2)
Y = 0 - YAxis/2;
The problem with this approach is that the angle will not be entirely accurate and the speed along the perimeter of the rectangle will not be constant. Modelling an ellipse that osculates the rectangle at its corners can minimize the effect, but if you are looking for a smooth, constant-speed "orbit," this method will not be adequate.
If think you mean rotate like the earth rotates around the sun (not the self-rotation... so your question is about how to slide along the edges of a rectangle?)
If so, you can give this a try:
# pseudo coode
for i = 0 to 499
if i < 100: x++
else if i < 250: y--
else if i < 350: x--
else y++
drawTheIcon(x, y)
Update: (please see comment below)
to use an angle, one line will be
y / x = tan(th) # th is the angle
the other lines are simple since they are just horizontal or vertical. so for example, it is x = 50 and you can put that into the line above to get the y. do that for the intersection of the horizontal line and vertical line (for example, angle is 60 degree and it shoot "NorthEast"... now you have two points. Then the point that is closest to the origin is the one that hits the rectangle first).
Use a 2D transformation matrix. Many languages (e.g. Java) support this natively (look up AffineTransformation); otherwise, write out a routine to do rotation yourself, once, debug it well, and use it forever. I must have five of them written in different languages.
Once you can do the rotation simply, find the location on the rectangle by doing line-line intersection. Find the center of the orbited icon by intersecting two lines:
A ray from your center of rotation at the angle you desire
One of the four sides, bounded by what angle you want (the four quadrants).
Draw yourself a sketch on a piece of paper with a rectangle and a centre of rotation. First translate the rectangle to centre at the origin of your coordinate system (remember the translation parameters, you'll need to reverse the translation later). Rotate the rectangle so that its sides are parallel to the coordinate axes (same reason).
Now you have a triangle with known angle at the origin, the opposite side is of known length (half of the length of one side of the rectangle), and you can now:
-- solve the triangle
-- undo the rotation
-- undo the translation

Resources