I am looking for a simple algorithm to pack <50 breps/mesh into a predefined rectangle. The goal is to have a fast tool not an good output. I would be all right to use the boundingboxes of the objects and it is really no problem to have some/much freespace. It is only important to have no overlapping objects.
I only find overcomplex grasshoper files im not able to transfer to c#.
Some hints?
For my tool Wordle in Nautilus that is very similar as packing I choose to use sort of pixel indeed array of bool. So each shape is an array of bool. I will surely implement soon a packing tool so it will be usable in any C# by referencing the library (LDLIB.dll).
But it seems to me as your problem is quite common you could use an existing project that do that. Something like, as it is C# most of the time the only job to do is adding some interface from and to Rhinocommon
A rectangle packing library for .NET Standard
Thankyou RectpackSharp was all i need.
protected override Result RunCommand(RhinoDoc doc, RunMode mode)
{
try
{
double resize_factor = 1000.0;
var count = 200;
uint area_height = Convert.ToUInt32(50 * resize_factor);
uint area_width = Convert.ToUInt32(100 * resize_factor);
var objects = GenerateTestObjects(count);
PackingRectangle[] rectangles = new PackingRectangle[objects.Count];
Dictionary<int, Sphere> obj_mapper = new Dictionary<int, Sphere>();
for (int i = 0; i < objects.Count; i++)
{
var obj = objects[i];
BoundingBox bb = obj.BoundingBox;
var corners = bb.GetCorners();
var bb_width = bb.Max.X - bb.Min.X;
var bb_height = bb.Max.Y - bb.Min.Y;
RhinoApp.WriteLine($"BB = x: {bb_width}, y: {bb_height}");
var width = Convert.ToUInt32(Math.Round(bb.Max.X - bb.Min.X, 3) * resize_factor);
var height = Convert.ToUInt32(Math.Round(bb.Max.Y - bb.Min.Y, 3) * resize_factor);
RhinoApp.WriteLine($"uintBB = x: {width}, y: {height}");
PackingRectangle packingRectangle = new PackingRectangle(0, 0, width, height, i);
RhinoApp.WriteLine($"packingRectangle = width: {packingRectangle.Width}, height: {packingRectangle.Height}, id: {packingRectangle.Id}");
rectangles[i] = packingRectangle;
obj_mapper.Add(i, obj);
}
RhinoApp.WriteLine($"rectangles = {rectangles.Length}");
RectanglePacker.Pack(rectangles, out PackingRectangle bounds, PackingHints.FindBest, 1.0, 1, null, area_height);
RhinoApp.WriteLine($"bounds = width: {Convert.ToDouble(bounds.Width) / resize_factor}, height: {Convert.ToDouble(bounds.Height) / resize_factor}");
foreach (var rect in rectangles)
{
var rhino_rec = new Rectangle3d(Rhino.Geometry.Plane.WorldXY, Convert.ToDouble(rect.Width) / resize_factor, Convert.ToDouble(rect.Height) / resize_factor);
Vector3d move_x = new Point3d(rect.X / resize_factor, 0, 0) - Point3d.Origin;
Vector3d move_y = new Point3d(0, rect.Y / resize_factor, 0) - Point3d.Origin;
var xform1 = Transform.Translation(move_x);
var xform2 = Transform.Translation(move_y);
rhino_rec.Transform(xform1);
rhino_rec.Transform(xform2);
var original_obj = obj_mapper[rect.Id];
Vector3d move_xy = rhino_rec.Center - original_obj.BoundingBox.Center;
original_obj.Translate(move_xy);
doc.Objects.AddCurve(rhino_rec.ToNurbsCurve());
doc.Objects.AddSphere(original_obj);
}
}
catch (Exception ex)
{
RhinoApp.WriteLine(ex.Message);
}
return Result.Success;
}
private List<Sphere> GenerateTestObjects(int count)
{
List<Sphere> spheres = new List<Sphere>();
for (int i = 0; i < count; i++)
{
var radius = GetRandomNumber(1.0, 10.0);
spheres.Add(new Sphere(Point3d.Origin, radius));
}
return spheres;
}
private double GetRandomNumber(double minimum, double maximum)
{
Random random = new Random((int)DateTime.Now.Ticks);
return random.NextDouble() * (maximum - minimum) + minimum;
}
This is my testcode with is creating this sample in 2-3 seconds:
I think the time could be speedup a lot using threading and dont post debug output to the rhinoconsole.
4 Likes
Thanks for showing what you get. It seems a powerful packing tool for rectangles.
Without the prints to Rhinoconsole it is nearly instandly. Really fast.
I will add it to my plugin, here 10000 ellipses in 143 ms!
I will add width or height to the default bin ratio of 1.
Nautilus version 1.9.3 contains this component
4 Likes