/* Subject: Contest submission for problem #2, file 2.java */
/* cs61a-mb@imail.EECS.Berkeley.EDU */
/* Thu Sep 18 16:17:54 PDT 2003 */
/*___CONTEST_SUBMISSION___ cs61a-mb 2 */

import java.awt.Color;
import java.awt.Graphics;
import java.awt.geom.Line2D;
import java.awt.geom.Point2D;
import java.io.EOFException;
import java.io.InputStreamReader;
import java.io.IOException;
import java.io.Reader;
import java.io.StreamTokenizer;
import java.text.DecimalFormat;
import java.util.ArrayList;
import java.util.Collection;
import java.util.Iterator;
import java.util.LinkedList;
import javax.swing.JFrame;
import javax.swing.JLabel;
import javax.swing.JPanel;
import javax.swing.JSlider;
import javax.swing.JTabbedPane;
import javax.swing.event.ChangeEvent;
import javax.swing.event.ChangeListener;

class P2 {
	public static void main(String[] args) {
		NumberStreamReader reader =
			new NumberStreamReader(new InputStreamReader(System.in));
		ArrayList scenarios = new ArrayList();
		int rectangles;

		try {
			while ((rectangles = (int) reader.readNumber()) != -1) {
				Scenario scenario =
					new Scenario(
						reader.readNumber(),
						reader.readNumber(),
						reader.readNumber(),
						reader.readNumber());

				for (int rectangle = 0; rectangle < rectangles; rectangle++) {
					scenario.addRectangle(
						reader.readNumber(),
						reader.readNumber(),
						reader.readNumber(),
						reader.readNumber(),
						reader.readNumber(),
						reader.readNumber());
				}

				scenarios.add(scenario);
			}

			if (args.length == 1 && args[0].equals("-gui")) {
				ScenarioDrawer drawer = new ScenarioDrawer();

				for (Iterator iterator = scenarios.iterator();
					iterator.hasNext();
					) {
					Scenario scenario = (Scenario) iterator.next();

					drawer.addScenario(scenario);
				}

				drawer.show();
			} else {
				for (int index = 0; index < scenarios.size(); index++) {
					Scenario scenario = (Scenario) scenarios.get(index);
					DecimalFormat format = new DecimalFormat("#.##");
					String length =
						format.format(scenario.getShortestPath().getLength());

					System.out.println("Scenario #" + (index + 1));
					System.out.println("   route distance: " + length);
				}
			}
		} catch (IOException exception) {
			exception.printStackTrace();
		}
	}
}

class ScenarioDrawer extends JFrame {
	private JTabbedPane scenarios = new JTabbedPane();

	public ScenarioDrawer() {
		super("Scenario Drawer");
		setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
		setSize(400, 400);
		getContentPane().add(scenarios);
	}

	public void addScenario(final Scenario scenario) {
		scenarios.addTab(
			"Scenario #" + (scenarios.getTabCount() + 1),
			new ScenarioPanel(scenario));
	}
}

class ScenarioPanel extends JPanel implements ChangeListener {
	private JLabel lengthLabel = new JLabel(), zoomLabel = new JLabel("x25");
	private JSlider slider = new JSlider(1, 50, 25);
	private Scenario scenario;

	public ScenarioPanel(Scenario scenario) {
		this.scenario = scenario;
		DecimalFormat format = new DecimalFormat("#.##");
		String length = format.format(scenario.getShortestPath().getLength());
		lengthLabel.setText("Shortest route: " + length);
		add(lengthLabel);
		slider.addChangeListener(this);
		add(slider);
		add(zoomLabel);
	}

	public void paint(Graphics graphics) {
		super.paint(graphics);

		graphics.setColor(Color.BLACK);
		drawLines(graphics, scenario.getLines());
		graphics.setColor(Color.RED);

		for (Iterator iterator = scenario.getPaths().iterator();
			iterator.hasNext();
			) {
			drawLines(graphics, (Path) iterator.next());
		}

		graphics.setColor(Color.GREEN);
		drawLines(graphics, scenario.getShortestPath());
	}

	public void stateChanged(ChangeEvent event) {
		zoomLabel.setText("x" + slider.getValue());
		repaint();
	}

	private void drawLines(Graphics graphics, Collection lines) {
		for (Iterator iterator = lines.iterator(); iterator.hasNext();) {
			Line2D line = (Line2D) iterator.next();

			graphics.drawLine(
				(int) (line.getX1() * slider.getValue()),
				getHeight() - (int) (line.getY1() * slider.getValue()),
				(int) (line.getX2() * slider.getValue()),
				getHeight() - (int) (line.getY2() * slider.getValue()));
		}
	}
}

class Path extends LinkedList {
	double length = 0.0D;

	public void addStep(Line2D line) {
		double x = line.getX2() - line.getX1();
		double y = line.getY2() - line.getY1();

		length += Math.sqrt(x * x + y * y);
		add(line);
	}

	public double getLength() {
		return length;
	}
}

class Scenario {
	private ArrayList lines = new ArrayList();
	private Point2D start, end;

	public Scenario(double x1, double y1, double x2, double y2) {
		start = new Point2D.Double(x1, y1);
		end = new Point2D.Double(x2, y2);
	}

	public void addRectangle(
		double x1,
		double y1,
		double x2,
		double y2,
		double x3,
		double y3) {
		Line2D.Double line1 = new Line2D.Double(x1, y1, x2, y2);
		Line2D.Double line2 = new Line2D.Double(x2, y2, x3, y3);

		if (arePerpendicular(line1, line2)) {
			double x4 = x1 + x3 - x2, y4 = y1 + y3 - y2;

			lines.add(line1);
			lines.add(line2);
			lines.add(new Line2D.Double(x3, y3, x4, y4));
			lines.add(new Line2D.Double(x4, y4, x1, y1));
		} else {
			addRectangle(x1, y1, x3, y3, x2, y2);
		}
	}

	public ArrayList getLines() {
		return lines;
	}

	public ArrayList getPaths() {
		return getPaths(start, end, new LinkedList(), new Path());
	}

	public Path getShortestPath() {
		ArrayList paths = getPaths();
		Path shortestPath = null;

		for (Iterator iterator = paths.iterator(); iterator.hasNext();) {
			Path path = (Path) iterator.next();

			if (shortestPath == null
				|| path.getLength() < shortestPath.getLength()) {
				shortestPath = path;
			}
		}

		return shortestPath;
	}

	private boolean arePerpendicular(Line2D line1, Line2D line2) {
		double line1Slope = calculateSlope(line1);
		double line2Slope = calculateSlope(line2);

		return line1Slope == -1.0D / line2Slope
			|| (Double.isInfinite(line1Slope)
				&& Double.isInfinite(-1.0D / line2Slope));
	}

	private double calculateSlope(Line2D line) {
		return (line.getY2() - line.getY1()) / (line.getX2() - line.getX1());
	}

	private ArrayList getPaths(
		Point2D start,
		Point2D end,
		LinkedList intersectedLines,
		Path path) {
		Line2D line = new Line2D.Double(start, end);
		ArrayList paths = new ArrayList();
		boolean intersects = false;

		for (Iterator iterator = getLines().iterator(); iterator.hasNext();) {
			Line2D rectangleLine = (Line2D) iterator.next();

			if (!intersectedLines.contains(rectangleLine)
				&& line.intersectsLine(rectangleLine)) {
				Path path1 = (Path) path.clone();
				Path path2 = (Path) path.clone();
				Point2D point1 = rectangleLine.getP1();
				Point2D point2 = rectangleLine.getP2();
				Line2D line1 = new Line2D.Double(start, point1);
				Line2D line2 = new Line2D.Double(start, point2);

				intersectedLines.add(rectangleLine);

				if (!intersectsLines(line1)) {
					path1.addStep(new Line2D.Double(start, point1));
					paths.addAll(
						getPaths(point1, end, intersectedLines, path1));
				}

				if (!intersectsLines(line2)) {
					path2.addStep(new Line2D.Double(start, point2));
					paths.addAll(
						getPaths(point2, end, intersectedLines, path2));
				}

				intersects = true;
			}
		}

		if (!intersects && !intersectsLines(line)) {
			path.addStep(line);
			paths.add(path);
		}

		return paths;
	}

	private boolean intersectsLines(Line2D line) {
		for (Iterator iterator = lines.iterator(); iterator.hasNext();) {
			Line2D intersectedLine = (Line2D) iterator.next();

			if (!(line.getP1().equals(intersectedLine.getP1())
				|| line.getP1().equals(intersectedLine.getP2())
				|| line.getP2().equals(intersectedLine.getP1())
				|| line.getP2().equals(intersectedLine.getP2()))
				&& line.intersectsLine(intersectedLine)) {
				return true;
			}
		}

		return false;
	}
}

class NumberStreamReader {
	private StreamTokenizer tokenizer;

	public NumberStreamReader(Reader reader) {
		tokenizer = new StreamTokenizer(reader);
	}

	public double readNumber() throws IOException {
		tokenizer.nextToken();

		switch (tokenizer.ttype) {
			case StreamTokenizer.TT_EOF :
				throw new EOFException();
			case StreamTokenizer.TT_NUMBER :
				return tokenizer.nval;
			default :
				throw new NumberFormatException();
		}
	}
}