Find the best layout(grid) for a given size - c#

I've a WPF custom panel, in which I want to layout several elements (in my case 12, but ideally I would like to find an algorithm that work for all) all with the same min width/height. The layout is a Grid, but I can choose the number of column/rows I want.
I would like to find a way to decide how many columns and how many rows I create, depending on the ratio of the window.
If the sub-elements had 1/1 ratio it would be easier; I would only have to compute the ratio for the possible layouts (admitting I've 12 sub-elements: 12/1, 6/2, 4/3, 3/4, 2/6, 1/12) and check which one is the closer to the panel width/height ratio.
But in my real case, I could set my sub-items twice as high as wide, so I'm a little bit lost on how to compute this? I guess I need to take their "ideal size", and then do some math between, but I don't know how.
Thank you!

After some experimentation and Unit Tests, I think I found a solution. In fact I don't need the width/height but just their ratio, same for elements.
I've the following class representing a Layout:
public class Layout : IEquatable<Layout>
{
public int RowCount { get; }
public int ColumnCount { get; }
public double Ratio { get; }
public Layout(int rowCount, int columnCount)
{
RowCount = rowCount;
ColumnCount = columnCount;
Ratio = (float)rowCount/columnCount;
}
}
And I've done the following to get the best layout:
public class LayoutAdapter
{
public Layout ComputeBestGridLayout(int elementsCount, double elementRatio, double panelRatio)
{
IEnumerable<Layout> possibleLayouts = GetPossibleLayouts(elementsCount);
return FindBestLayouts(possibleLayouts, elementRatio, panelRatio);
}
private IEnumerable<Layout> GetPossibleLayouts(int elementCounts)
{
//TODO Increment "elementsCounts", because maybe with some hole we will have a better match for the ratio
List<Layout> acceptedResults =new List<Layout>();
for (int i1 = 0; i1 <= elementCounts; i1++)
{
double rest2 = elementCounts%((double) i1);
if (rest2 == 0)
{
int i2 = elementCounts/i1;
acceptedResults.Add(new Layout(i1,i2));
}
}
return acceptedResults;
}
private Layout FindBestLayouts(IEnumerable<Layout> possibleLayouts, double elementRatio, double panelRatio)
{
Layout closestLayout = null;
double minDiff=Double.MaxValue;
foreach (Layout possibleLayout in possibleLayouts)
{
double currentDiff = Math.Abs((panelRatio/ elementRatio) - possibleLayout.Ratio);
if (currentDiff < minDiff)
{
minDiff = currentDiff;
closestLayout = possibleLayout;
}
}
return closestLayout;
}
}

Related

C# Optimize Conditional in Loop where input is a value that needs to be between a start/end value found in each list item

EDIT: This is a general problem when you are stuck in a situation that you have to use a List instead of a Dictionary because instead of searching for a key you may be searching for a range of number like a text minimum and maximum index, and each item may have inner items in them, in my case it added up to 100k+ items before I found a workable solution just after posting this question.
Solution below involves partitioning the list into smaller chunks, much like database indexing.
I call the following a lot in a particular project. It works fine, but there's a problem with this as far as optimization is concerned. I have an index and need to get all text spans where the index is between the start and end, as shown below.
Example:
List<Lexer.Span> spans = new List<Lexer.Span>();
for (int i1 = 0; i1 < input.OrganizedSpans.Count; i1++)
{
Lexer.Span span1 = input.OrganizedSpans[i1];
if (index >= span1.Start && index < span1.End) { spans.Add(span1); }
}
...
public class Lexer {
...
public class Span
{
public int Start {get;set;}
public int End {get;set;}
public string Text {get;set;}
public List<Span> InnerSpans {get;set;} = new List<Span>();
}
}
OrganizedSpans has 6,000+ items stemming from lexemes tokenized of an 18k HTML document, so it gets weighed down significantly doing a straight iteration. I will show you a partitioning optimization in the answer that will help in situations like this. It brought my execution down from a few seconds to near-instantaneous.
Original: It works, but is a bottleneck according to the Visual Studio Profiler on the if conditional line. It gets called quite a bit from the parser code.
Is there a faster way to do what I want to do here? I've looked at several optimization articles and stackoverflow posts, but am having trouble finding it.
UPDATE: Yes there is. :)
The answer is simple, partition your lists into smaller lists, here's an example code:
List Partition Building, replace Span and Lexer for whatever you need to partition, in my case it was a syntax node tree of text from an LL(1) parser:
public class LexerResult
{
public class ResultPartition
{
public int Minimum { get; set; }
public int Maximum { get; set; }
public List<Span> Spans { get; set; }
}
public List<Span> RawSpans { get; set; }
public List<Span> OrganizedSpans { get; set; }
public List<ResultPartition> OrganizedPartitions { get; set; }
...
Partition Method:
public List<LexerResult.ResultPartition> OrganizePartitions(List<Span> spans, int partitionSize = 300)
{
List<LexerResult.ResultPartition> partitions = new List<LexerResult.ResultPartition>();
bool done = false;
int recordsProcessed = 0;
while(!done)
{
int recordsNeeded = 0;
if (recordsProcessed + partitionSize > spans.Count)
{
recordsNeeded = spans.Count - recordsProcessed;
done = true;
}
else
{
recordsNeeded = partitionSize;
}
int recordsNeededEnd = recordsProcessed + recordsNeeded;
int min = Int32.MaxValue;
int max = Int32.MinValue;
List<Span> partition = new List<Span>();
for(int i=recordsProcessed;i<recordsNeededEnd;i++)
{
Span span = spans[i];
min = Math.Min(span.Start, min);
max = Math.Max(span.End, max);
partition.Add(span);
}
recordsProcessed += recordsNeeded;
LexerResult.ResultPartition resultPartition = new LexerResult.ResultPartition()
{
Spans = partition,
Maximum = max,
Minimum = min
};
partitions.Add(resultPartition);
}
return partitions;
}
Usage:
List<Lexer.Span> spans = new List<Lexer.Span>();
for(int i1=0;i1<input.OrganizedPartitions.Count;i1++)
{
Lexer.LexerResult.ResultPartition partition = input.OrganizedPartitions[i1];
if (partition.Minimum <= index && index < partition.Maximum)
{
List<Lexer.Span> spans_1a = partition.Spans;
for (int i3 = 0; i3 < spans_1a.Count; i3++)
{
Lexer.Span span_1a = spans_1a[i3];
if (span_1a.Start <= index && index < span_1a.End)
{
spans.Add(span_1a);
}
}
}
...
}
Note: Using for instead of foreach does seem to clock faster in Visual Studio's Profiler.
So I'm taking a minimum and maximum from each span and building partitions that have a min/max property you can use for easily seeing which data points have a start and end surrounding whatever index you supply.
I didn't see this mentioned on any of the articles and posts I read about optimizing .NET code so it seemed worth mention. The program I'm writing is running near-instantaneous and soon to be released after some testing/documentation.

Point Classification in a set of Bounding Boxes

I have a set of bounding boxes(rectangular) in a 3D space. The bounds of each box are computed and stored in a dictionary named "RegionBounds". Also, a set of points are populated in a List named "PointsToCategorize" Given a point(x,y,z) coordinates from the List populated and a bounding box to be checked in, i can check if the point is inside the box or not. The problem is, this is a big dataset. The number of points to be checked are like 1000 and the no of bounding boxes are like 250-300. So, if i loop through each bounding box for each given point; the total time it takes is like 5-6 minutes. Is there any efficient method that would do the process quicker ? If possible, a small code to do so would be great
public struct iBounds {
public double x1, x2;
public double y1, y2;
public double z1, z2;
}
public struct iPoint {
public double x,y,z
}
Dictionary<String, iBounds> RegionBounds = new Dictionary<String, iBounds>();
List<iPoint> PointsToCategorize = new List<iPoint>();
int no_of_bounding_boxes = 300;
int no_of_points_to_categorize = 1000;
for (int i = 1; i <= no_of_bounding_boxes; i++)
{
String boundingBoxName = "bound_" + i;
iBounds boundingBox = new iBounds
{
x1 = Computed By Some Other method and Formulas,
x2 = Computed By Some Other method and Formulas,
y1 = Computed By Some Other method and Formulas,
y2 = Computed By Some Other method and Formulas,
z1 = Computed By Some Other method and Formulas,
z2 = Computed By Some Other method and Formulas
};
RegionBounds.Add(boundingBoxName, boundingBox);
}
////////////Start of Output section /////////////////////////
for(int i= 1; i < = PointsToCategorize.Count; i++){
foreach(var pair in RegionBounds)
{
String myboxNmame = pair.Key;
iBounds myboxBounds = pair.Value;
Console.WriteLine(PointInside(PointsToCategorize[i],myboxBounds).ToString());
}
}
////////////// End of Output section //////////////////
private bool PointInside(iPoint mypoint, iBounds boxToBeCheckedIn)
{
if (mypoint.x > boxToBeCheckedIn.x1) && (mypoint.x < boxToBeCheckedIn.x2){
if (mypoint.y > boxToBeCheckedIn.y1) && (mypoint.y < boxToBeCheckedIn.y2){
if (mypoint.z > boxToBeCheckedIn.z1) && (mypoint.z < boxToBeCheckedIn.z2){
return true;
}
}
}else{
return false;
}
}
You may want to use a OcTree or a kD-tree data structure, which is way more efficient than iterating through all the boxes.
See also this article at the section 2-D orthogonal range searching, it has a very good resume of available techniques and algorithms, which are easily extendable to 3D

LBG algorithm - can I use existing k-means algorithm for it?

I'm writing a program comparing the working of k-means and LBG algorithm.
I have a k-means algorithm written, which accepts a list of Points and number of clusters, and then draws them on the screen in different colors. It returns me a list of clusters which have a list of points assigned to them.
Now, my question is: can I somehow modify my k-means to get LBG algorithm? I tried searching online for a step by step explanation of LBG, but wikipedia only has 3 sentences on it, I've found mathlab explanation which consists of 4 lines of code, and the original paper which you have to buy. Could someone explain/point me to a guide for this?
Thank you.
Edit: Please, no very hard technical papers, I can't read them properly yet with my english.
Edit2: Here is code for my k-means class:
public class k_means
{
public static List<Punktyzbior> oblicz(Punktyzbior punkty, int klasterctr)
{
List<Punktyzbior> wszystkieklastry = new List<Punktyzbior>();
List<List<Punkt>> wszystkiegrupy = pomocnicze_listy.PodzielListe<Punkt>(punkty, klasterctr);
foreach (List<Punkt> grupa in wszystkiegrupy)
{
Punktyzbior klaster = new Punktyzbior();
klaster.AddRange(grupa);
wszystkieklastry.Add(klaster);
}
int przejscia = 1;
while (przejscia > 0)
{
przejscia = 0;
foreach (Punktyzbior klaster in wszystkieklastry)
{
for (int punktIdx = 0; punktIdx < klaster.Count; punktIdx++)
{
Punkt punkt = klaster[punktIdx];
int najblizszyklaster = znajdzNajblizszy(wszystkieklastry, punkt);
if (najblizszyklaster != wszystkieklastry.IndexOf(klaster))
{
if (klaster.Count > 1)
{
Punkt usunPunkt = klaster.usunPunkt(punkt);
wszystkieklastry[najblizszyklaster].dodajPunkt(usunPunkt);
przejscia += 1;
}
}
}
}
}
return (wszystkieklastry);
}
public static int znajdzNajblizszy(List<Punktyzbior> wszystkieklastry, Punkt punkt)
{
double minOdl = 0.0;
int najblizszyCIdx = -1;
for (int k = 0; k < wszystkieklastry.Count; k++)
{
double odl = Punkt.znajdzOdl(punkt, wszystkieklastry[k].c);
if (k == 0)
{
minOdl = odl;
najblizszyCIdx = 0;
}
else if (minOdl > odl)
{
minOdl = odl;
najblizszyCIdx = k;
}
}
return (najblizszyCIdx);
}
}
Instead of trying to get from kmeans to LBG I would rather try to "translate" this java code to c#, it would be a lot easier I think.
Try to do it, and if you have a specific problem with the implementation come back and let us know.
https://github.com/internaut/JGenLloydCluster/blob/master/src/net/mkonrad/cluster/GenLloyd.java

Efficient AABB/triangle intersection in C#

Can anyone recommend an efficient port to CSharp of any of the public AABB/triangle intersection algorithms.
I've been looking at Moller's approach, described abstractly here, and if I were to port it, I would probably start from this C++ version. This C++ library by Mike Vandelay seems like it could also be a great starting point.
...or... any other "wheel" that can take a triangle of Vector3's and tell me if it intersects with an AABB), relatively efficiently.
There seem to be a variety of algorithms, but most seem to be written in c++, or just described abstractly in white papers and I need a c# specific implementation for our application. Efficiency is not key, but c# is. (though efficiency is obviously nice too of course ;p )
Any C# options, before I wade through a "math" port ;) would be greatly appreciated! Thanks.
For any two convex meshes, to find whether they intersect, you need to check if there exist a separating plane. If it does, they do not intersect. The plane can be picked from any face of either shape, or the edge cross-products.
The plane is defined as a normal and an offset from Origo. So, you only have to check three faces of the AABB, and one face of the triangle.
bool IsIntersecting(IAABox box, ITriangle triangle)
{
double triangleMin, triangleMax;
double boxMin, boxMax;
// Test the box normals (x-, y- and z-axes)
var boxNormals = new IVector[] {
new Vector(1,0,0),
new Vector(0,1,0),
new Vector(0,0,1)
};
for (int i = 0; i < 3; i++)
{
IVector n = boxNormals[i];
Project(triangle.Vertices, boxNormals[i], out triangleMin, out triangleMax);
if (triangleMax < box.Start.Coords[i] || triangleMin > box.End.Coords[i])
return false; // No intersection possible.
}
// Test the triangle normal
double triangleOffset = triangle.Normal.Dot(triangle.A);
Project(box.Vertices, triangle.Normal, out boxMin, out boxMax);
if (boxMax < triangleOffset || boxMin > triangleOffset)
return false; // No intersection possible.
// Test the nine edge cross-products
IVector[] triangleEdges = new IVector[] {
triangle.A.Minus(triangle.B),
triangle.B.Minus(triangle.C),
triangle.C.Minus(triangle.A)
};
for (int i = 0; i < 3; i++)
for (int j = 0; j < 3; j++)
{
// The box normals are the same as it's edge tangents
IVector axis = triangleEdges[i].Cross(boxNormals[j]);
Project(box.Vertices, axis, out boxMin, out boxMax);
Project(triangle.Vertices, axis, out triangleMin, out triangleMax);
if (boxMax <= triangleMin || boxMin >= triangleMax)
return false; // No intersection possible
}
// No separating axis found.
return true;
}
void Project(IEnumerable<IVector> points, IVector axis,
out double min, out double max)
{
double min = double.PositiveInfinity;
double max = double.NegativeInfinity;
foreach (var p in points)
{
double val = axis.Dot(p);
if (val < min) min = val;
if (val > max) max = val;
}
}
interface IVector
{
double X { get; }
double Y { get; }
double Z { get; }
double[] Coords { get; }
double Dot(IVector other);
IVector Minus(IVector other);
IVector Cross(IVector other);
}
interface IShape
{
IEnumerable<IVector> Vertices { get; }
}
interface IAABox : IShape
{
IVector Start { get; }
IVector End { get; }
}
interface ITriangle : IShape {
IVector Normal { get; }
IVector A { get; }
IVector B { get; }
IVector C { get; }
}
A good example is the box (±10, ±10, ±10) and the triangle (12,9,9),(9,12,9),(19,19,20). None of the faces can be used as a separating plane, yet they do not intersect. The separating axis is <1,1,0>, which is obtained from the cross product between <1,0,0> and <-3,3,0>.
I noticed a small bug in this implementation which leads to false negatives.
If your triangle has one edge parallel to one axis (for example (1, 0, 0)), then you will have a null vector when computing
triangleEdges[i].Cross(boxNormals[j])
This will lead to equality in the test below and give you a false negative.
replace <= and >= by < and > at line
if (boxMax <= triangleMin || boxMin >= triangleMax)
(strict comparers to remove those cases).
Works well except for that!
Thank you

Problems with double array?

I am required to create a program which reads in data from a .cvs file, and use these (x, y and z) values for a series of calculations.
I read in the file as a string, and then split this into 3 smaller strings for x, y and z.
The x, y and z coordinates represents the x and y coordinates of the contours of a lake, and the depth (z).
One of the calculations which I have to do, is to calculate the surface area of the lake, using the formula (x[i]*y[i+1])-(x[i+1]*y[i]), where z(depth) = 0.
I can get my code to run perfectly, up until the x[i+1] and y[i+1], where it keeps giving me a value of 0.
Can someone please tell me how to fix this?
Here is my code;
{
string[] ss = File.ReadAllLines(#"C:File.csv");
for (int i = 1; i < ss.Length; i++)
{
string[] valuesAsString = ss[i].Split(new char[] { ' ', ',' }, StringSplitOptions.RemoveEmptyEntries);
double[] X = new double[valuesAsString.Length];
double[] Y = new double[valuesAsString.Length];
double[] Z = new double[valuesAsString.Length];
for (int n = 0; n < 1; n++)
{
X[n] = double.Parse(valuesAsString[0]);
Y[n] = double.Parse(valuesAsString[1]);
}
do
{
double SurfaceArea = (X[n] * Y[n + 1]) - (X[n + 1] * Y[n]);
Console.WriteLine(SurfaceArea);
}
while (Z[n] == 0);
}
}
Ok, im not sure if i got it right, so you if you would take a look to what i did and tell me if its of any help.
After reviewng it a little i came up with the following:
A class for the values
public class ValueXyz
{
public double X { get; set; }
public double Y { get; set; }
public int Z { get; set; }
}
A class to manange the calculation:
public class SurfaceCalculator
{
private ValueXyz[] _valuesXyz;
private double _surface;
private readonly string _textWithValues;
public SurfaceCalculator(string textWithValues)
{
_textWithValues = textWithValues;
SetValuesToCalculate();
}
public double Surface
{
get { return _surface; }
}
public void CalculateSurface()
{
for (var i = 0; i < _valuesXyz.Length; i++)
{
if (_valuesXyz[i].Z == 0)
_surface = (_valuesXyz[i].X*_valuesXyz[i + 1].Y) - (_valuesXyz[i + 1].X*_valuesXyz[i].Y);
}
}
private void SetValuesToCalculate()
{
var valuesXyz = _textWithValues.Split(' ');
_valuesXyz = valuesXyz.Select(item => new ValueXyz
{
X = Convert.ToDouble(item.Split(',')[0]),
Y = Convert.ToDouble(item.Split(',')[1]),
Z = Convert.ToInt32(item.Split(',')[2])
}).ToArray();
}
}
So now your client code could do somethin like:
[TestMethod]
public void TestSurfaceCalculatorGetsAValue()
{
//var textWithValues = File.ReadAllText(#"C:File.csv");
var textWithValues = "424.26,424.26,0 589.43,231.46,0 720.81,14.22,1";
var calculator = new SurfaceCalculator(textWithValues);
calculator.CalculateSurface();
Assert.IsNotNull(calculator.Surface);
}
I'm not very sure i got the idea correct of how to implement the formula, but i just wanted to expose an alternative you can use, you can never have to many ways of doing one thing :).
Cheers.
By the way part of the intent i had, was not tying up your funcionality to the csv in case your source for the text in the future would change.
Step through your code in the debugger. Pay special attention to tbe behavior of the line
for (int n = 0; n < 1; n++)
This loop will execute how many times? What will the value of n be during each iteration through the loop?
Well, one thing i noticed is when you're setting your X, Y, Z vars, you're setting it to the Length of the array object instead of it's value - is that intentional?
Put a debug break on the line with:
double SurfaceArea = (X[n] * Y[n + 1]) - (X[n + 1] * Y[n]);
and check the datatype of "X", "Y" and "Z"
I've had problems in the past where it tries to calculate them as strings (because it took it out of the data source as strings). I ended up fixing it by adding CInt() to each of the variables (or Convert.ToInt32();).
Hope this helps.
As this looks like it might be a homework problem, I am trying not to give a direct solution in my answer, but I see a number of questionable parts of your code that you should examine.
Why are X, Y, Z arrays? You are creating a new array each time through the outer loop, setting the length of the array to the number of elements in the line, then only assigning a value to one element of X and Y, and never assigning Z to anything.
As phoog suggests in his answer, what is the purpose of: for (int n = 0; n < 1; n++)?
What are you trying to accomplish with the do-while loop? As it has been mentioned in the comments by Mr Skeet, X[n], Y[n], Z[n] don't exist because n does not exist outside of the loop it is declared for. Even if it did exist Z[n] will always be zero because you never assign anything to the Z array after it is initialized, so the do-while loop will run forever.

Categories

Resources