5
$\begingroup$

I'd like to sample points on a triangle randomly. The following code yields points that are uniformly distributed on a quadrilateral:

random points in triangle

point = RandomReal[]*(v2-v1) + RandomReal[]*(v3-v1);

I'd like to take advantage of the symmetry and transform points chosen outside the triangle to their reflected position inside the triangle. It seems like this should be simple with ReflectionTransform, but so far, no dice. Here's some code to demonstrate:

Module[{vertices = {{0, 0, 0}, {1, 0, 0}, {0, 1, 1}}, p, r},

 p = (RandomReal[] vertices[[2]] - vertices[[1]]) +
     (RandomReal[] vertices[[3]] - vertices[[1]]);

 r = ReflectionTransform[p];

 Print["p=", p]; Print["r[p]=", r[p]];

 Show[Graphics3D[{Red, Triangle[vertices]}], 
      Graphics3D[{Blue, PointSize[0.02], Point[vertices], Green, 
                  PointSize[0.04], Point[p], Point[r[p]]}], 
      Graphics3D[Text[#, 1.05 #] &/@(vertices~Join~{p, r[p]})]]]

what I tried

Obviously, the reflection above is not specified properly, but I would like to reflect the point, P, in the plane of the triangle to generate two corresponding points mirrored over the edge (v2 -> v3).

$\endgroup$
4
3
$\begingroup$

Other folks have comments on other techniques for doing the sampling, but I wanted to address how you could actually do it with ReflectionTransformation—or, more accurately, why you should do it with RotationTransformation instead.

ReflectionTransform[p] reflects points about the origin by default; it also points the "mirror" in the direction from the origin to p. Given this, applying ReflectionTransform[p] to p itself will always yield -p. The correct syntax to reflect the point p about a plane containing vertices[[2]] and vertices[[3]] and perpendicular to the plane of the triangle is this:

r = ReflectionTransform[Cross[vertices[[2]] - vertices[[3]],
                          Cross[vertices[[2]] - vertices[[1]], vertices[[3]] - vertices[[1]]]], 
                        vertices[[2]]]

To decipher this:

  • Define $\vec{A}$ and $\vec{B}$ as the vectors pointing from vertices[[1]] to vertices[[2]] and vertices[[3]], respectively. These are found by subtracting vertices[[1]] from vertices[[2]] and vertices[[3]].
  • The normal vector to the mirror is the first argument of ReflectionTransform. We find this by taking the double cross product $(\vec{A} - \vec{B}) \times (\vec{A} \times \vec{B})$. $\vec{A} \times \vec{B}$ is always perpendicular to the plane of the triangle; the plane of the "mirror" will contain both this vector and $(\vec{A} - \vec{B})$, so we take the cross product of the two to obtain the normal to the mirror.
  • The second argument of ReflectionTransform is any point along the line connecting vertices[[2]] and vertices[[3]]; either one of the points themselves will do nicely.

With all that said: this is probably not the transformation you want, for the simple reason that it doesn't always yield points that lie in the lower left-hand triangle. It will if the original parallelogram is reflection-symmetric about the diagonal in question; but that's not the case for most parallelograms. (Try folding a piece of A4/Letter paper across the diagonal to see what I mean.) I suspect that instead of reflecting about a plane containing the diagonal, you would rather rotate about the midpoint of the diagonal:

r = RotationTransform[Pi, Cross[vertices[[2]] - vertices[[1]], vertices[[3]] - vertices[[1]]], (vertices[[2]] + vertices[[3]])/2]

This creates a rotation of $\pi = 180$° about the axis $\vec{A} \times \vec{B}$ (so perpendicular to the plane of the parallelogram) about the midpoint of the side containing vertices[[2]] and vertices[[3]]. This will always map points from the "upper" triangle" into the "lower" triangle.

$\endgroup$
4
$\begingroup$

This is not quite a direct answer to your question, but if the end result is to have points sampled on a triangle, maybe the following would help:

SeedRandom[1]

triangle = Triangle[{{0, 0, 0}, {1, 1, 1}, {0, 1, 1}}];

Graphics3D[{
  Red, triangle,
  Green, Ball[RandomPoint[triangle, 10], 0.02]
}]

3D triangle with random points represented as green balls

A caveat: RandomPoint is new to Mathematica version 10.2

$\endgroup$
2
4
$\begingroup$

To answer the question in the title:

lineReflect[p0_?VectorQ, {p1_?VectorQ, p2_?VectorQ}] /; MatrixQ[{p0, p1, p2}] :=
            2 p1 - p0 + 2 Projection[p0 - p1, p2 - p1]

A demonstration:

GraphicsRow[{Graphics[{AbsolutePointSize[4],
                       Point[{2, 4/3}], Line[{{1, 1}, {3, 2}}], 
                       Point[lineReflect[{2, 4/3}, {{1, 1}, {3, 2}}]]}], 
             Graphics3D[{AbsolutePointSize[4],
                         Point[{2, 4/3, 1/2}], Line[{{1, 1, 0}, {3, 1, 2}}], 
                         Point[lineReflect[{2, 4/3, 1/2}, {{1, 1, 0}, {3, 1, 2}}]]}]}]

reflection about a line


I'd like to sample points on a triangle randomly.

To answer the actual need of the OP, one can use DirichletDistribution[] with RandomVariate[], as already noted:

With[{v1 = {1, 0, 0}, v2 = {0, -1, 0}, v3 = {0, 0, 1}}, (* triangle poins *)
     BlockRandom[SeedRandom[42, Method -> "Legacy"]; (* for reproducibility *)
                 Graphics3D[Point[Append[#, 1 - Total[#]].{v1, v2, v3} & /@ 
                                  RandomVariate[DirichletDistribution[{1, 1, 1}],
                                                5000]]]]]

random points in a triangle

If, for some reason, you can't or don't want to use DirichletDistribution[], here's how to do what I call the "fold-over":

With[{v1 = {1, 0, 0}, v2 = {0, -1, 0}, v3 = {0, 0, 1}}, 
     Graphics3D[Point[Table[
                With[{pt = RandomReal[1, 2]}, 
                     v1 + If[Total[pt] <= 1, pt, 1 - pt].{v2 - v1, v3 - v1}],
                            {5000}]]]]

which should yield a qualitatively similar picture.

$\endgroup$
0

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.