473,386 Members | 1,924 Online
Bytes | Software Development & Data Engineering Community
Post Job

Home Posts Topics Members FAQ

Join Bytes to post your question to a community of 473,386 software developers and data experts.

Circular Layout

RedSon
5,000 Expert 4TB
Hi all,

I have a problem where I have 1..n icons that I would like to layout in a circular pattern. Starting at an origin of (120, 160) I'm trying to figure out how to iterate over the collection of items and assign them a new position offset from the origin. Each of these items is a square of 48px and they cannot overlap.

How in the world do I do it? I know I'll be needing to use my trig on this, but it's been so long I forgot most of it :(

Thanks.
Jan 27 '09 #1
28 7566
Dormilich
8,658 Expert Mod 8TB
roughly speaking they need a distance of about 75px (48px · 2^0.5) from each other, the direction depends on the number n. so minimum radius of the circle should be n · 75px / 2 pi for n > 4 (to make it a sensible approximation).

..... if I've understood the problem right.

edit>>>
if you have a symmetry group of D[(2n)d] (i.e. an even number of pictures) you can reduce the calculation effort to one fourth (otherwise, one half)
<<<
Jan 27 '09 #2
RedSon
5,000 Expert 4TB
Here is what I have now (link):

Expand|Select|Wrap|Line Numbers
  1. Vector2 origin = new Vector2(viewport.Width / 2, viewport.Height / 2);
  2.  
  3. int radius = 48;
  4. double factor = ((2 * Math.PI) / menuEntries.Count);
  5.  
  6. // Draw each menu entry in turn.
  7. foreach (MenuEntry entry in menuEntries.Values)
  8. {
  9.     int i = menuEntries.IndexOfValue(entry);
  10.     bool isSelected = IsActive && (i == selectedEntry);
  11.  
  12.     iconPos.X = (float)radius * (float)Math.Cos(factor * i + 1);
  13.     iconPos.Y = (float)radius * (float)Math.Sin(factor * i + 1);
  14.  
  15.     entry.Draw(this, Vector2.Add(iconPos,origin), isSelected, gameTime);
  16. }
Now there is no way I can tell if there are an even number of pictures or not, but I would be interested in optimizing the calculations.

The radius will likewise need to be calculated but it is currently hard coded.

Is this implementation close to what you were thinking?
Jan 27 '09 #3
Dormilich
8,658 Expert Mod 8TB
@RedSon
yes, the only thing I wonder is why you use an initial rotation of 57° 17′ 44.8″.

you should check if the radius given is large enough, so that the icons do not overlap.
Expand|Select|Wrap|Line Numbers
  1. r(min) = n · icon.width / ( sqroot(2) · pi ) 
note that this approximation does not work for n < 5, thus a good default radius is necessary (48px should do)

for drawing optimization compute the circle with the origin at (0, 0) and add position on screen later. (seems like you already did that)

you can use a rotation matrix
Expand|Select|Wrap|Line Numbers
  1. cos(a)    –sin(a)
  2. sin(a)     cos(a)
so you only need to compute the first point and then repeatedly (n–1 times) apply the matrix in a iterative way.
Expand|Select|Wrap|Line Numbers
  1. x(0) = r · sin(a_ini)
  2. y(0) = r · cos(a_ini)
  3. // a_ini is the initial angle you want, 0 is vertical, top
  4.  
  5. x(i+1) = x(i) · cos(a) – y(i) · sin(a);
  6. y(i+1) = x(i) · sin(a) + y(i) · sin(a)
  7. // where a = 2·pi / n
note: I don't know how to code in C#
Jan 28 '09 #4
JosAH
11,448 Expert 8TB
Are those icons shown in an upright position (i.e. no tilt)?

kind regards,

Jos
Jan 28 '09 #5
RedSon
5,000 Expert 4TB
@Jos: The icons in my application are not rotated in any way when they are drawn on the screen.

@Dormilich: Why do you say I use an initial rotation of 57° 17′ 44.8″?

Also, I would use this formula
Expand|Select|Wrap|Line Numbers
  1. r(min) = n · icon.width / ( sqroot(2) · pi )
but the screen size is so small having 5 or more icons creates a great amount of clutter. Is there a way to modify this such that r(min) can be calculated for n > 1?
Jan 28 '09 #6
RedSon
5,000 Expert 4TB
Also would either of you be willing to do some code review on the project I linked to in post 3?

You can use the web based svn viewer and double click on any line to make comments on that line. You don't have to know C# to be able to intuit what is going on with it.
Jan 28 '09 #7
Dormilich
8,658 Expert Mod 8TB
@RedSon
Expand|Select|Wrap|Line Numbers
  1. Math.Cos(factor * i + 1)
57° 17′ 44.8″ = 1 (rad),
like usual in maths, if you add in y = f(x) a value to x, you shift the function by –x

@RedSon
sure,
n = 2: r(min) = 0.5 · icon.width;
n = 3: r(min) = sqroot(2/3) · icon.width;
n = 4: r(min) = icon.width;

@RedSon
the formula is an approximation of the circumference calculation, which will give large deviations for small n.
Jan 28 '09 #8
Dormilich
8,658 Expert Mod 8TB
@RedSon
If I don't have to do it until next week, I'll try my best.
Jan 28 '09 #9
RedSon
5,000 Expert 4TB
You don't have to do it until whenever you want to do it. There is no project schedule for this, it is a hobby of mine.
Jan 28 '09 #10
RedSon
5,000 Expert 4TB
@Dormilich
Of course, that didn't even occur to me! I will have to make a fix for that, since I would like it to start at 0.
Jan 28 '09 #11
Dormilich
8,658 Expert Mod 8TB
that's good.

if you would in turn have a look at my PHP code........ (though I need to find a place to post the code first)
Jan 28 '09 #12
RedSon
5,000 Expert 4TB
I would look at it, however I find PHP code to be much more cryptic than C#, so I am not sure how useful I will be. :(
Jan 28 '09 #13
Dormilich
8,658 Expert Mod 8TB
it's more about programm design than actual coding (I know that my PHP knowledge is above forum average, but that doesn't mean I can't overlook some crucial points, especially since I'm new to OOP coding)
Jan 28 '09 #14
RedSon
5,000 Expert 4TB
Well, just got to find a place to put it ;-)
Jan 28 '09 #15
JosAH
11,448 Expert 8TB
For a fast upperbound you can do this; an icon at 45 degrees takes up most of the space, i.e. sqrt(2)*48 == W pixels (its diagonal). For n icons in a 'circular' layout you need a circumpherence of n*W pixels. That basically solves it; note that not all icons will 'touch' eachother because this estimation is a minimal upperbound.

kind regards,

Jos
Jan 28 '09 #16
Dormilich
8,658 Expert Mod 8TB
@Dormilich
@JosAH: like that one? (only put in a formula)

note: this solution does not work for n = 4, you'll see the overlap in some cases (the minimum radius is calculated 10% too small)
Jan 28 '09 #17
JosAH
11,448 Expert 8TB
@Dormilich
No not like that one; I reread my reply and noticed that my description was extremely sloppy. When you chop up a circle in equal angle wedges, those wedges are all isosecles triangles. The sides opposite to the centre of the circle should equal sqrt(2)*W, not that part of the circumpherence of the circle.

kind regards,

Jos
Jan 29 '09 #18
Dormilich
8,658 Expert Mod 8TB
ok, you can exactly calculate the r(min) for every n by using the Law of Cosines, nevertheless, for n > 4 the approximation by circle segments is good enough and far easier to compute.

Alas, I see our discussion is interesting, but pointless, because RedSon said 5 or more icons would be too much for his application.
Jan 29 '09 #19
YarrOfDoom
1,247 Expert 1GB
This has caught my interest. I didn't see this solution anywhere, but wouldn't the perfect formula for for calculating the minimum radius be:
Expand|Select|Wrap|Line Numbers
  1. (sqrt(2) * 24) / sin(pi / n)
I've tried this on my graphical calculator and it seems to work for every n>1.
Here's how I got to it:

Feb 16 '09 #20
RedSon
5,000 Expert 4TB
I'm assuming 24 to be dependent on the dimension of the icon? How would your formula change if the icons could have an arbitrary height and width (but still be square)?
Feb 16 '09 #21
Dormilich
8,658 Expert Mod 8TB
@YarrOfDoom
well, I was not aiming for the perfect formula (since this would involve sines or cosines), just one easy and fast to compute. and, put in another way, you have to round it anyways in the end (to get the pixels).

EDIT: using the Law of Cosines I get:
Expand|Select|Wrap|Line Numbers
  1. r = w / sqrt(1 – cos(2pi/n))
Feb 16 '09 #22
YarrOfDoom
1,247 Expert 1GB
@RedSon
It would become (sqrt(2) * x) / (2 * sin(pi / n))

@Dormilich
I guess it all depends on the situation, but it's always handy to have a more general solution standby, in case you come across a similar situation.
Feb 16 '09 #23
RedSon
5,000 Expert 4TB
@YarrOfDoom
Yes I know but my question was, what is x defined as? Is it half the width of the icon if the icon is square?
Feb 16 '09 #24
YarrOfDoom
1,247 Expert 1GB
@RedSon
Oops, lost a line there, x represents the width (and height, since it's a square) of the icon, and also note that the sine is multiplied by 2 now. (So the 24 is indeed meant as one half of 48).
Feb 16 '09 #25
bvdet
2,851 Expert Mod 2GB
RedSon,

I found this thread by accident since I don't get over here often. For the exercise, I worked up a general solution in Python using code from one of my modules.
Expand|Select|Wrap|Line Numbers
  1. from math import pi, sin
  2.  
  3. from macrolib.PointPlane3D import *
  4.  
  5. def icon_layout(origin, size, n):
  6.  
  7.     # calculate radius
  8.     minChord = size*2**0.5
  9.     angleBetween = 2*pi/n
  10.     minRadius = (minChord/2)/sin(angleBetween/2)
  11.  
  12.     startPoint = Point(origin.x+minRadius, origin.y, 0)
  13.     '''
  14.     Three counter-clockwise points define a plane with the plane normal
  15.     vector pointing out of the screen. First point is the center of
  16.     rotation. Second point defines the X axis and radius of circle.
  17.     '''
  18.     A = Plane3D(origin, startPoint, 
  19.                 Point(origin.x, origin.y+minRadius, 0))
  20.  
  21.     return [A.PointRotate3D(startPoint, angleBetween*i) \
  22.             for i in range(numberIcons)]
  23.  
  24. origin = Point(120, 160, 0)
  25. iconSize = 48
  26. numberIcons = 12
  27. pointList = icon_layout(origin, iconSize, numberIcons)
  28. for pt in pointList:
  29.     print repr(pt)
Output:
Expand|Select|Wrap|Line Numbers
  1. >>> Point(251.138439, 160.000000, 0.000000)
  2. Point(233.569219, 225.569219, 0.000000)
  3. Point(185.569219, 273.569219, 0.000000)
  4. Point(120.000000, 291.138439, 0.000000)
  5. Point(54.430781, 273.569219, 0.000000)
  6. Point(6.430781, 225.569219, 0.000000)
  7. Point(-11.138439, 160.000000, 0.000000)
  8. Point(6.430781, 94.430781, 0.000000)
  9. Point(54.430781, 46.430781, 0.000000)
  10. Point(120.000000, 28.861561, 0.000000)
  11. Point(185.569219, 46.430781, 0.000000)
  12. Point(233.569219, 94.430781, 0.000000)
  13. >>>
If you are interested in the source code for PointPlane3D: link

Here's a graphical solution:
Attached Images
File Type: jpg circular_layout.jpg (15.0 KB, 632 views)
Apr 2 '09 #26
gtoal
2
I don't think any of these solutions are taking into account a visually pleasing layout where the amount of white space between each icon is roughly similar. in 'circular_layout.jpg' above where the icons are regularly spaced, you can see where the icons at 45 degrees almost touch but the vertically or horizontally adjacent ones have a gap. A smarter algorithm that takes the shortest distance between the nearest points of adjacent icons into account may be needed.
Oct 13 '11 #27
Dormilich
8,658 Expert Mod 8TB
a smarter algorithm would just add padding to the icon width.
Oct 14 '11 #28
Let your icons be squares of sides a. Define a regular polygon of n sides with side d=a*sqrt(2). You can count from d and n the radius of the circle around the polygon:
r=(d/2)/sin(2*pi/n).
Place the center points of your icons on the vertices of this polygon.
x(k)= C(x)+r*cos(k/(2*pi),
y(k)= C(y)+r*sin(k/(2*pi), k=0,1,2,...,n-1.
Nov 15 '11 #29

Sign in to post your reply or Sign up for a free account.

Similar topics

1
by: Henry Miller | last post by:
I have the following code (much simplified for this post). Note that SessionKey uses DataAccess, and DataAccess requires SessionKey in it's constructor. Public Class SessionKey Public...
2
by: ernesto basc?n pantoja | last post by:
Hi everybody: I'm implementing a general C++ framework and I have a basic question about circular dependencies: I am creating a base class Object, my Object class has a method defined as:...
16
by: Kiuhnm | last post by:
Is there an elegant way to deal with semi-circular definitions? Semi-circular definition: A { B }; B { *A }; Circular reference: A { *B }; B { *A }; The problems arise when there are more...
2
by: Earth Worm Jim | last post by:
I have been able to get simple circular references to be serialized in xml by using the ImportTypeMapping method on the SoapReflectionImporter class. But I am unable to serialise circular...
12
by: Frank Rizzo | last post by:
I have a circular reference between 2 classes in the same project (i.e. each class refers to the other). The app runs fine and I am seeing no issues, which kind of surprised me. Are there any...
6
by: Stephen Robertson | last post by:
We are currently in a dead end with a circular reference issue using vb.net, and are hoping someone might help us resolve it. Idea... We have frmmain calling frmperson (dim f as new frmperson)...
7
by: toton | last post by:
Hi, I have a STL vector of of characters and the character class has a Boost array of points. The things are vector<Characterchars; and class Character{ private: array<Point,Npoints; }; Now...
7
by: barias | last post by:
Although circular dependencies are something developers should normally avoid, unfortunately they are very easy to create accidentally between classes in a VS project (i.e. circular compile-time...
53
by: brave1979 | last post by:
Please check out my javascript library that allows you to create any layout for your web page, nested as deep as you like, adjusting to width and height of a browser window. You just describe it in...
0
by: Charles Arthur | last post by:
How do i turn on java script on a villaon, callus and itel keypad mobile phone
0
by: ryjfgjl | last post by:
In our work, we often receive Excel tables with data in the same format. If we want to analyze these data, it can be difficult to analyze them because the data is spread across multiple Excel files...
0
by: emmanuelkatto | last post by:
Hi All, I am Emmanuel katto from Uganda. I want to ask what challenges you've faced while migrating a website to cloud. Please let me know. Thanks! Emmanuel
0
BarryA
by: BarryA | last post by:
What are the essential steps and strategies outlined in the Data Structures and Algorithms (DSA) roadmap for aspiring data scientists? How can individuals effectively utilize this roadmap to progress...
1
by: nemocccc | last post by:
hello, everyone, I want to develop a software for my android phone for daily needs, any suggestions?
0
by: Hystou | last post by:
There are some requirements for setting up RAID: 1. The motherboard and BIOS support RAID configuration. 2. The motherboard has 2 or more available SATA protocol SSD/HDD slots (including MSATA, M.2...
0
marktang
by: marktang | last post by:
ONU (Optical Network Unit) is one of the key components for providing high-speed Internet services. Its primary function is to act as an endpoint device located at the user's premises. However,...
0
by: Hystou | last post by:
Most computers default to English, but sometimes we require a different language, especially when relocating. Forgot to request a specific language before your computer shipped? No problem! You can...
0
jinu1996
by: jinu1996 | last post by:
In today's digital age, having a compelling online presence is paramount for businesses aiming to thrive in a competitive landscape. At the heart of this digital strategy lies an intricately woven...

By using Bytes.com and it's services, you agree to our Privacy Policy and Terms of Use.

To disable or enable advertisements and analytics tracking please visit the manage ads & tracking page.