Juxtapose two triangles with a common edge

704 Views Asked by At

I'm not experto in geometry but I'm trying to do a software that handle triangles in various way. And I'm trying to learn geometry, of course : )

I have one fixed triangles $T1 = \hat{ABC}$ and a second triangle $T2 = \hat{DEF}$. I want to translate and rotate the second triangle so that the edge $AB$ overlaps the edge $DE$.

I think the right war is to handle the ray that goes from the middle point of BC and goes into the direction of the centroid of the second triangle. If I have the direction of that ray I can easily translate $T2$ and rotate it to the angle between BC and DE.

But I can't understand how do it even after a day of facing it. So I'm asking some helps. In particular when I'm doing it fine for one of the test case above in the other test case the ray is not facing in the right direction.

Here some numbers (I'm coding with Java but just to give numbers), and the respective visual result I'm expecting:

void initializeTriangle0() {
    a = new Vec2D(-100, -100);
    b = new Vec2D(100, -100);
    c = new Vec2D(0, 100);
    t1 = new Triangle2D(a,b,c);
    edgeABC = new Line2D(b,c);

    d = new Vec2D(-100, -200);
    e = new Vec2D(100, -100);
    f = new Vec2D(0, 100);
    t2 = new Triangle2D(d,e,f);
    edgeDEF = new Line2D(d,e);
}

enter image description here

void initializeTriangle1() {
    a = new Vec2D(229.28932f, 300.0f);
    b = new Vec2D(335.35535f, 406.27783f);
    c = new Vec2D(335.35535f, 193.72217f);
    t1 = new Triangle2D(a,b,c);
    edgeABC = new Line2D(b,c);

    d = new Vec2D(-35.355347f, -106.27784f);
    e = new Vec2D(-35.35533f, 106.27784f);
    f = new Vec2D(70.71068f, 5.0964204E-6f);
    t2 = new Triangle2D(d,e,f);
    edgeDEF = new Line2D(d,e);
}

enter image description here

void initializeTriangle2() {
    a = new Vec2D(433.5996f, 233.33334f);
    b = new Vec2D(233.2002f, 233.33334f);
    c = new Vec2D(233.2002f, 433.33334f);
    t1 = new Triangle2D(a,b,c);
    edgeABC = new Line2D(b,c);

    d = new Vec2D(-66.666664f, 66.666664f);
    e = new Vec2D(133.33334f, 66.666664f);
    f = new Vec2D(-66.666664f, -133.33334f);
    t2 = new Triangle2D(d,e,f);
    edgeDEF = new Line2D(d,e);
}

enter image description here

EDIT:

the last image is actually wrong because I'm expecting C===D && B===E

1

There are 1 best solutions below

1
On BEST ANSWER

There are some inconsistencies in the question (e.g. talking about the edge $AB$, but using (b,c) in the code), but I think that the general intention became clear.

Admittedly, I did not fully understand your ray+centroid approach. However, here's a suggestion about how I would do it:

Given the edges that you want to align, compute the angle between these edges, and the centers of the edges. Then you can rotate the second triangle around the edge center about the angle that is required to make the edges parallel. Then, move the triangle, so that the edge center is at the same location as the center of the other edge.

You must be careful about the direction of the edges and the orientation of the triangles. Depending on wheter both triangles are oriented equally (both clockwise or both counterclockwise), and depending on whether you chose the edge $DE$ or $ED$, you'll have to add another rotation about $\pi$ - but it should be easy to figure this out for the particular case.

I just implemented this, using plain Java2D. So I'm using Point2D instead of the unknown Vec2D class etc - but the idea should become clear. The program allows dragging the corners of the right (pale blue) triangle, and it displays the aligned (dark blue) triangle.

enter image description here

import java.awt.Color;
import java.awt.Graphics;
import java.awt.Graphics2D;
import java.awt.RenderingHints;
import java.awt.Shape;
import java.awt.event.MouseEvent;
import java.awt.event.MouseListener;
import java.awt.event.MouseMotionListener;
import java.awt.geom.AffineTransform;
import java.awt.geom.Line2D;
import java.awt.geom.Path2D;
import java.awt.geom.Point2D;
import java.io.IOException;
import java.util.ArrayList;
import java.util.List;

import javax.swing.JFrame;
import javax.swing.JPanel;
import javax.swing.SwingUtilities;


public class TriangleAlignTest
{
    public static void main(String[] args) throws IOException
    {
        SwingUtilities.invokeLater(new Runnable()
        {
            @Override
            public void run()
            {
                createAndShowGUI();
            }
        });
    }

    private static void createAndShowGUI()
    {
        JFrame f = new JFrame();
        f.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
        f.getContentPane().add(new TriangleAlignTestPanel());
        f.setSize(900,500);
        f.setLocationRelativeTo(null);
        f.setVisible(true);
    }
}

class Triangle2D
{
    private final Point2D p0;
    private final Point2D p1;
    private final Point2D p2;

    Triangle2D(List<Point2D> points)
    {
        this(points.get(0), points.get(1), points.get(2));
    }

    Triangle2D(Point2D p0, Point2D p1, Point2D p2)
    {
        this.p0 = new Point2D.Double(p0.getX(), p0.getY());
        this.p1 = new Point2D.Double(p1.getX(), p1.getY());
        this.p2 = new Point2D.Double(p2.getX(), p2.getY());
    }

    public Point2D getPoint(int index)
    {
        if (index == 0)
        {
            return p0;
        }
        if (index == 1)
        {
            return p1;
        }
        return p2;
    }

    Shape getShape()
    {
        Path2D path = new Path2D.Double();
        path.moveTo(p0.getX(), p0.getY());
        path.lineTo(p1.getX(), p1.getY());
        path.lineTo(p2.getX(), p2.getY());
        path.closePath();
        return path;
    }

    Triangle2D transformed(AffineTransform at)
    {
        Point2D tp0 = at.transform(p0, null);
        Point2D tp1 = at.transform(p1, null);
        Point2D tp2 = at.transform(p2, null);
        return new Triangle2D(tp0, tp1, tp2);
    }

}

class TriangleAlignTestPanel extends JPanel
    implements MouseListener, MouseMotionListener
{
    private final List<Point2D> points0;
    private final List<Point2D> points1;
    private Point2D draggedPoint = null;

    TriangleAlignTestPanel()
    {
        Point2D a = new Point2D.Double(-100, -100);
        Point2D b = new Point2D.Double(100, -100);
        Point2D c = new Point2D.Double(0, 100);

        Point2D d = new Point2D.Double(-100, -200);
        Point2D e = new Point2D.Double(100, -100);
        Point2D f = new Point2D.Double(0, 100);

        AffineTransform at0 = AffineTransform.getTranslateInstance(150, 150);
        a = at0.transform(a, null);
        b = at0.transform(b, null);
        c = at0.transform(c, null);

        AffineTransform at1 = AffineTransform.getTranslateInstance(550, 250);
        d = at1.transform(d, null);
        e = at1.transform(e, null);
        f = at1.transform(f, null);

        points0 = new ArrayList<Point2D>();
        points0.add(a);
        points0.add(b);
        points0.add(c);

        points1 = new ArrayList<Point2D>();
        points1.add(d);
        points1.add(e);
        points1.add(f);

        addMouseListener(this);
        addMouseMotionListener(this);
    }


    @Override
    protected void paintComponent(Graphics gr)
    {
        super.paintComponent(gr);
        Graphics2D g = (Graphics2D)gr;
        g.setRenderingHint(
            RenderingHints.KEY_ANTIALIASING,  
            RenderingHints.VALUE_ANTIALIAS_ON);
        g.setColor(Color.WHITE);
        g.fillRect(0, 0, getWidth(), getHeight());

        // Create the triangles
        Triangle2D t0 = new Triangle2D(points0);
        Triangle2D t1 = new Triangle2D(points1);

        // Obtain the edges
        Line2D e0 = new Line2D.Double(t0.getPoint(1), t0.getPoint(2));
        Line2D e1 = new Line2D.Double(t1.getPoint(0), t1.getPoint(1));

        // Compute the centers of the edges
        Point2D center0 = at(e0, 0.5);
        Point2D center1 = at(e1, 0.5);

        // Compute the angle of the edges to the x-axis
        double a0 = angle(e0);
        double a1 = angle(e1);

        // Compute the alignment transformation:
        // Second: Translate the triangle so that the edge centers match
        AffineTransform at = new AffineTransform();
        at.concatenate(AffineTransform.getTranslateInstance(
            center0.getX()-center1.getX(), center0.getY()-center1.getY()));
        // First: Rotate the triangle so that the angles are equal
        at.concatenate(AffineTransform.getRotateInstance(
            Math.PI+a0-a1, center1.getX(), center1.getY()));
        Triangle2D tt1 = t1.transformed(at);

        g.setColor(Color.RED);
        draw(g, t0);
        g.setColor(new Color(0,0,255,32));
        draw(g, t1);
        g.setColor(Color.BLUE);
        draw(g, tt1);

    }

    private static double angle(Line2D line)
    {
        double x0 = line.getX1();
        double y0 = line.getY1();
        double x1 = line.getX2();
        double y1 = line.getY2();
        double x = x1-x0;
        double y = y1-y0;
        return Math.atan2(y, x);
    }

    private static Point2D at(Line2D line, double position)
    {
        double x0 = line.getX1();
        double y0 = line.getY1();
        double x1 = line.getX2();
        double y1 = line.getY2();
        double x = x0 + position * (x1-x0);
        double y = y0 + position * (y1-y0);
        return new Point2D.Double(x, y);
    }

    private static void draw(Graphics2D g, Triangle2D t)
    {
        g.draw(t.getShape());
        for (int i=0; i<3; i++)
        {
            Point2D p = t.getPoint(i);
            int x = (int)p.getX();
            int y = (int)p.getY();
            g.drawString(String.valueOf(i), x, y);
        }
    }

    @Override
    public void mouseDragged(MouseEvent e)
    {
        if (draggedPoint != null)
        {
            draggedPoint.setLocation(e.getPoint());
            repaint();
        }
    }

    @Override
    public void mouseMoved(MouseEvent e)
    {
    }

    @Override
    public void mouseClicked(MouseEvent e)
    {
    }

    @Override
    public void mousePressed(MouseEvent e)
    {
        draggedPoint = null;
        double thresholdSquared = 10*10;
        double minDs = Double.MAX_VALUE;
        for (Point2D point : points1)
        {
            double ds = point.distanceSq(e.getPoint());
            if (ds < thresholdSquared && ds < minDs)
            {
                minDs = ds;
                draggedPoint = point;
            }
        }
    }

    @Override
    public void mouseReleased(MouseEvent e)
    {
        draggedPoint = null;
    }

    @Override
    public void mouseEntered(MouseEvent e)
    {
    }

    @Override
    public void mouseExited(MouseEvent e)
    {
    }


}