12

Say we have this path:

enter image description here

How do we find the bounds of the box that fits inside?

Yes I know that paths can be arbitrarily complex and must not be closed. Still curious about suggestions for how to solve this problem.

Johan Larsson
  • 17,112
  • 9
  • 74
  • 88
  • What's so hard? The bounding box is between maximum and minimum x and y coordinates. – Ben Mar 16 '16 at 21:45
  • @Ben I think the issue is how does he find the max and min coordinates within the shape... Things like the rounded corners make it more difficult. – Reed Copsey Mar 16 '16 at 22:57
  • 1
    For sure you need to provide starting coordinates for the algorithm, because searching for a box in the middle of the bubble will bear different results than if you started inside the triangle below. This is even more true for more comples paths. – Robert Synoradzki Mar 17 '16 at 12:14
  • you should probably post the path coordinates to get an answer on this. this looks like something which would be fun to fiddle around with. however most people are lazy - throwing problems at their feet increases your chances on getting a solution instead of just raising then question ;) – Dbl May 12 '16 at 19:23
  • @Kylo Ren do you need balloons like in the pic? – Johan Larsson May 12 '16 at 20:09
  • @JohanLarsson no.... my question is what your question was? – Kylo Ren May 13 '16 at 04:04
  • Not clear if you want to solve this for your specific shape (or similar), or in the general case? If it's general, you should provide more information, and a list of test cases. – Simon Mourier May 13 '16 at 06:37
  • You need max rectangle that can be put inside of the path, or min rectangle that will wrap path (so will be outside)? – Evk May 13 '16 at 08:36
  • 1
    Max rectangle that can be put in the path, path can be arbitrary. I posted this question in case there is some nice theory to read about this problem. – Johan Larsson May 13 '16 at 08:44
  • Are you sure that for any given path there's always only one solution? But assuming that that's the case, and we're dealing with a polygon, I'd start with finding the largest convex polygon built from the subset of the path's points. I think it can be argued that the solution lies within that convex polygon. Then the problem can be divided into smaller ones - note that such a rectangle would always "touch" at most four edges, so it would suffice to solve for each such tuple of edges (and many could be rejected by checking simple conditions) and select the best solution. – Grx70 May 13 '16 at 17:16
  • 2
    Also, you might want to take a look at [this paper](http://kam.mff.cuni.cz/~hansraj/publications/rectangle.pdf). – Grx70 May 13 '16 at 17:33
  • @Grx70 I'm sure there are many paths where there is no solution, non-closed ones for example. Also for something simple like an ellipse there is an infinite number of boxes, which one is best? Max area? Thanks for the link! [Ear clipping](http://www.geometrictools.com/Documentation/TriangulationByEarClipping.pdf) can perhaps be a starting point also. – Johan Larsson May 13 '16 at 18:42
  • So I left a really long answer for the specific shape that you listed in your question but now reading through the comments I see that you are looking for something more general. The convex polygon idea isn't going to help since not every shape will have a maximum convex polygon. To see this try to think of the convex polygon that best approximates a circle and you will quickly see that for every polygon that you choose the next one with one more side is a better approximation meaning that a circle is effectively an infinite sided polygon in a sense. – Chiune Sugihara May 13 '16 at 22:01
  • Thinking about it some more you are probably looking for more of an approximate algorithm than a mathematical solution. In the cases where you would want to add an interior box you would almost certainly be dealing with a shape that isn't too crazy otherwise it would just look goofy (think of a dumbell shape where there are two largest by area interior boxes of which you have to pick one for an idea of goofy). So I think what you really just want to do is go with something quick and dirty that starts in the center and grows a rectangle until it doesn't fit anymore. Thoughts? – Chiune Sugihara May 13 '16 at 22:25
  • @ChiuneSugihara Yeah, that is what I though of as well but decided to not implement it and let the caller set margins for the content instead. Have an upvote for the answer. I asked the question because I was curious but I almost regret asking after all the attention with a bounty and all. – Johan Larsson May 13 '16 at 23:24
  • @Kylo please edit the question if there is something specific you want with the bounty. – Johan Larsson May 13 '16 at 23:24
  • @JohanLarsson - Understood. I think the short answer to your question is that it isn't possible since a shape can have multiple, distinct largest interior rectangles in general (for instance the dumbell shape can have two distinct largest interior rectangles). So I think it boils down to cases where you have just one and in that case you are probably dealing with something fairly tame that you could just approximate the center with by averaging some points that you used to create the path and then growing out the largest rectangle you can or else just set margins that look roughly correct. – Chiune Sugihara May 13 '16 at 23:41
  • @ChiuneSugihara You're correct with your circle example. Maybe I didn't stress it enough, but the convex polygon idea was based on an assumption that we're starting off with a polygon (thus rejecting ellipses, non-closed paths etc.). – Grx70 May 15 '16 at 10:46
  • I was also considering an "inflate" concept. But what would be a good strategy - where to start and how to proceed? One idea for a starting point would be a [centroid](https://en.wikipedia.org/wiki/Centroid). On the other hand, coming back to the WPF world, maybe it would be easier to start off with the path's bounding box and "deflate" it (perhaps "towards" the centroid). – Grx70 May 15 '16 at 10:57
  • Off the cuff I would say approximate the center, create a trivially small rectangle to start with and then keep extending it in on a single side until it can no longer be extended (where each extension results in another rectangle). I would imagine this would be pretty effective for paths like the one from this question or others fairly similar to it. – Chiune Sugihara May 15 '16 at 20:28
  • @JohanLarsson I'm super busy right now sorry for the delay, i couldn't find the code i wanted some rework on, will try to update it tomorrow. but my basic problem is just If I have a shape, i wanted to draw a rectangle inside it so that i can display some text in that.. I just thought that if i could find the max rectangle size I can write more text.. does this make sense. – Kylo Ren May 16 '16 at 18:18

1 Answers1

3

I guess to start I would go with a simple answer. The jut out on the bottom clearly won't affect the size of the largest interior rectangle so we can just assume that you can omit that. Once that is omitted it seems to me to be something like just two RectangleGeometries that have been combined that have their RadiusX and RadiusY properties being non-zero.

An approximation that I made is given by the xaml below:

<Path Fill="Black">
    <Path.Data>
        <CombinedGeometry GeometryCombineMode="Xor">
            <CombinedGeometry.Geometry1>
                <RectangleGeometry Rect="10,10,100,50" RadiusX="5" RadiusY="5" />
            </CombinedGeometry.Geometry1>
            <CombinedGeometry.Geometry2>
                <RectangleGeometry Rect="15,15,90,40" RadiusX="5" RadiusY="5"/>
            </CombinedGeometry.Geometry2>
        </CombinedGeometry>
    </Path.Data>
</Path>

To me your question boils down to how to in general find the largest rectangle that will fit inside of the interior RectangleGeometry without overlapping its border. To do that we have to deal with the RadiusX and RadiusY values.

To simplify things for now I will assume that RadiusX = RadiusY != 0 and if you happen to be interested in the case of RadiusX != RadiusY != 0 then we can cross that bridge when we get to it.

When the x and y radii are equal the curved corner is just traced out using a circle. This circle will shorten the interior space given the way that it works and given that the radius values are small relative to the width and height of your image you are probably looking for the bounding rectangle that fits touches the 45 degree angle of the curved corners.

To accomplish this we just need to figure out the width and height that we are losing for a single corner. Since we are talking a circle and considering the 45 degree angle the losses will be the same in both directions. Using some simple trigonometry I came up with the following loss amount given a radius value of R:

loss for single corner direction = R(1 - sqrt(2)/2)

This was derived by determining the distance from the corner of the non-rounded version to the 45 degree edge of the rounding circle. This length can just be gathered by using the Pythagorean theorem to determine the length of the radius of the circle plus the "missing" portion and then just subtracting out the known radius to determine the length of the hypotenuse for this "missing" portion which is equal to R(1 - sqrt(2)).

Once this distance was gathered I used trigonometry again to gather the size of the legs of the resulting isosceles triangle which came out to R(1 - sqrt(2)/2) which is the equation that I listed earlier.

So finally, assuming that the original rectangle without any rounding would have x = x_o, y = y_o, width = w_o, height = h_o, and R = RadiusX = RadiusY != 0 we would get the following for our inscribed rectangle:

x = x_o + R(1 - sqrt(2)/2)
y = y_o + R(1 - sqrt(2)/2)
width = w_o - 2R(1 - sqrt(2)/2)
height = h_o - 2R(1 - sqrt(2)/2)

I tested this with the following xaml:

<Path Stroke="Black">
    <Path.Data>
         <RectangleGeometry Rect="10,10,100,50" RadiusX="5" RadiusY="5"/>
    </Path.Data>
</Path>
<Path Stroke="Orange">
     <Path.Data>
         <RectangleGeometry Rect="11.47,11.47,97.07,47.07" RadiusX="0" RadiusY="0"/>
    </Path.Data>
</Path>

Now this doesn't take into account the actual strokes of each rectangle geometry which do overlap but the interiors do not overlap which is what I am assuming is what you are looking for.

I know that there are a fair number of assumptions and simplifications flying around here but even with all of those this is a very long post so I am hoping that this is good enough for what you are looking for.

Nawed Nabi Zada
  • 2,819
  • 5
  • 29
  • 40
Chiune Sugihara
  • 1,179
  • 1
  • 7
  • 14