MathGroup Archive 1999

[Date Index] [Thread Index] [Author Index]

Search the Archive

Re: Convex Hull

  • To: mathgroup at smc.vnet.net
  • Subject: [mg20947] Re: [mg20839] Convex Hull
  • From: Daniel Lichtblau <danl at wolfram.com>
  • Date: Wed, 1 Dec 1999 01:50:14 -0500 (EST)
  • References: <199911170840.DAA02595@smc.vnet.net>
  • Sender: owner-wri-mathgroup at wolfram.com

Virgil Stokes wrote:
> 
> My problem is this:
> 
>   I have two ellipses that in general are different (lengths of minor/major
>   axes may differ) and are positioned at random in the XY-plane
>   with the condition that they do not overlap or touch at any point along their
>   boundaries.
> 
>   The problem is to find the convex hull for these two ellipses -- fast.
>   Any ideas/suggestions would be appreciated
> 
>   Please reply direct to my email since I am still unable to get messages
> generated
>   from the MathGroup list.
> 
> -- Virgil

Here is a reasonable method. It works when the ellipses are presented in
implicit form. I checked via e-mail that specifically they will have the
form

(x-a)^2/e^2 + (y-b)^2/f^2 == 1

The code given will actually work more generally with pairs of implicit
curves. I'll set this up using indeterminate coefficients, then fill
them in with random values. The first thing to realize is that the
convex hull will be comprised of two arcs (one from each ellipse) and
two line segments that each intersect both ellipses tangentially. To
find these we'll need the pairs of points. These we get just by solving
a system of polynomial equations.

ellipse1 = (x-a1)^2/p1^2 + (y-b1)^2/q1^2 - 1;
ellipse2 = (x-a2)^2/p2^2 + (y-b2)^2/q2^2 - 1;

slope1 = First[yprime /. Solve[
	(D[ellipse1/.y->y[x],x] /. {y[x]->y, y'[x]->yprime}) == 0, yprime]];
slope2 = First[yprime /. Solve[
	(D[ellipse2/.y->y[x],x] /. {y[x]->y, y'[x]->yprime}) == 0, yprime]];

rules1 = {x->x1, y->y1};
rules2 = {x->x2, y->y2};
polys = Numerator[Together[{ellipse1/.rules1, ellipse2/.rules2,
	(slope1/.rules1)-(slope2/.rules2),
	(y2-y1)-(slope1/.rules1)*(x2-x1)}]];

These polynomials are exactly what must be satisfied in order for the
pair of points {{x1,y1}, {x2,y2}} to satisfy:
(i) {xj,yj} lies on ellipsej.
(ii) The tangents to ellipsej through {xj,yj} have the same slopes.
(iii) {x2,y2} lies on the tangent to ellipse1 through {x1,y1}.

Now we'll make random substitutions to get two actual ellipses.

SeedRandom[1111]
replacements = Join[
	Thread[{a1,b1}->Table[Random[Real,{2,5}],{2}]],
	Thread[{a2,b2}->Table[Random[Real,{-5,-2}],{2}]],
	Thread[{p1,q2}->Table[Random[Real,{.3,.9}],{2}]],
	Thread[{p2,q1}->Table[Random[Real,{1.5,3}],{2}]]];
{ell1, ell2} = {ellipse1,ellipse2} /. replacements;


Next we find all such pairs of points. For two quadratic plane curves we
get four solutions. In some cases two might be complex valued. In
particular this will happen if the ellipses intersect. While it is
stipulated that this situation does not occur, we'll explicitly take
only real-valued solutions to make this code fairly general.

In[145]:= pairs = Cases[
        {{x1,y1},{x2,y2}} /. NSolve[polys/.replacements, {x1,y1,x2,y2}],
        {{_Real,_Real}, {_Real,_Real}}]
                    
Out[145]= {{{4.49236, 6.30875}, {-5.76366, -4.49148}}, 
    {{4.24555, 5.8998}, {-0.0761669, -4.60452}}, 
    {{5.18463, 2.67326}, {-0.0907271, -4.63022}}, 
    {{4.99884, 2.48789}, {-5.70571, -4.44488}}}


Now we need to determine which two pairs give the convex hull segments
and which do not. One way to find this is as follows: the midpoints of
the other three segments must all lie on the same side of the line
through a given hull segment. The code below will use this fact to find
the correct two segments.

midpoint[{p1_,p2_}] := (p1+p2)/2
slope[{p1_,p2_}] := (p2[[2]]-p1[[2]]) / (p2[[1]]-p1[[1]])

sameside[pair:{p1_,p2_}, midpts:{mid1_,mid2_,mid3_}] := Module[
	{x, y, m=slope[pair], line, signs},
	line = (y-p1[[2]]) - m*(x-p1[[1]]);
	Apply[Equal, Map[Sign,
	  line /. Map[Thread[{x,y}->#]&, midpts]]]
	]

getHullPoints[e1_, e2_, pairs:{pair1_, pair2_, pair3_, pair4_}] :=
Module[
	{midpts, pointdata},
	pointdata = MapIndexed[{#1, midpoint[#1],#2}&, pairs];
	midpts = Map[#[[2]]&, pointdata];
	Map[First, Select[pointdata, sameside[#[[1]],
          Drop[midpts,#[[3]]]]&]]
	]

hullpts = getHullPoints[ell1, ell2, pairs]

One can readily put this together in a picture.

plot1 = ContourPlot[ell1, {x,-8,8}, {y,-8,8}, Contours->{0},
	PlotPoints->200, ContourShading->False,
	DisplayFunction->Identity];
plot2 = ContourPlot[ell2, {x,-8,8}, {y,-8,8}, Contours->{0},
	PlotPoints->200, ContourShading->False,
	DisplayFunction->Identity];
lines = Map[Graphics[Line[#]]&, hullpts];
Show[plot1, plot2, Apply[Sequence,lines],
	DisplayFunction->$DisplayFunction];

A final step might be to convert the ellipses to parametric form and
only use the two arcs that lie on the hull. These in turn can be deduced
either by checking angles with the tangent segments or by a slight
variation of the midpoints-on-one-side technique.


Daniel Lichtblau
Wolfram Research


  • Prev by Date: Re: goto & Findmininimum
  • Next by Date: Research of Penrose tilings needed!
  • Previous by thread: Re: the new @@@ thing, MapApply?
  • Next by thread: Research of Penrose tilings needed!