import java.io.*; import java.util.*; public class international_mb_2boundaries_cosmaxbug { static final class Point { final double x, y; Point(double x, double y) { this.x = x; this.y = y; } Point add(Vector v) { return new Point(x + v.x, y + v.y); } double dist2(Point that) { double dx = x - that.x; double dy = y - that.y; return dx * dx + dy * dy; } Vector vectorTo(Point that) { return new Vector(that.x - x, that.y - y); } } static final class Vector { final double x, y; Vector(double x, double y) { this.x = x; this.y = y; } Vector rotate(double cos, double sin) { return new Vector(x * cos - y * sin, x * sin + y * cos); } double len2() { return x * x + y * y; } Vector scale(double multiple) { return new Vector(x * multiple, y * multiple); } Vector scale2d(double forward, double orthogonal) { return new Vector(x * forward - y * orthogonal, y * forward + x * orthogonal); } double scalarProduct(Vector that) { return x * that.x + y * that.y; } double crossProduct(Vector that) { return x * that.y - y * that.x; } } static final class Circle { final Point c; final double r; Circle(Point c, double r) { this.c = c; this.r = r; } } // Produce a triangle with given edge lengths and vertices in given circles, // such that first two vertices lie on the boundaries of the first two circles, // or return null. // The orientation of the triangle is given by signum: // a positive value means the cross-product of (p0--p1) and (p0--p2) is positive static Point[] triangleBoundaryMatch(Circle c0, Circle c1, Circle c2, double dsq01, double dsq02, double dsq12, double signum) { return new TriangleBoundaryMatcher(c0, c1, c2, dsq01, dsq02, dsq12, signum).result; } static class TriangleBoundaryMatcher { final Circle c0, c1, c2; final double dsq01, dsq02, dsq12; final double d01, d02, d12; final double dcsq01, dc01; final double signum; final Vector c0c1n; final double angleMin, angleMax; final double scale2fwd, scale2ort; Point[] result; TriangleBoundaryMatcher(Circle c0, Circle c1, Circle c2, double dsq01, double dsq02, double dsq12, double signum) { this.c0 = c0; this.c1 = c1; this.c2 = c2; this.dsq01 = dsq01; this.dsq02 = dsq02; this.dsq12 = dsq12; this.signum = signum; this.d01 = Math.sqrt(dsq01); this.d02 = Math.sqrt(dsq02); this.d12 = Math.sqrt(dsq12); this.dcsq01 = c0.c.dist2(c1.c); this.dc01 = Math.sqrt(dcsq01); this.c0c1n = c0.c.vectorTo(c1.c).scale(c0.r / dc01); // cos of angle at point0 is (dsq01 + dsq02 - dsq12) / (2 * d01 * d02) // we will have a vector of length d01 // we need to rotate it by this angle and make it of length d02 // so we multiply that cos by d02 / d01, which makes (dsq01 + dsq02 - dsq12) / (2 * dsq01) this.scale2fwd = (dsq01 + dsq02 - dsq12) / (2 * dsq01); // the orthogonal weight is same as sin, but scaled by d02 / d01 all the way through this.scale2ort = signum * Math.sqrt(Math.max(0, dsq02 / dsq01 - scale2fwd * scale2fwd)); // By validation in directMatch, // we know there is a way to put a 01-segment into circles c0 and c1 // Now we are in the new coordinate system: // c0 is at (0;0), c1 is at (dc01;0) // and we are trying the ways to put endpoints of a segment of length d01 into these circles. // A segment can be put in four different ways: // - y on c0 can be negative or positive // - y on c1 can be negative or positive // The angle ranges can sometimes merge, but we process them separately, // as any monotonic behaviour changes at y=0 // This is how we compute the angle ranges double cosMax = c0.r == 0 ? 0 : (c0.r * c0.r + dcsq01 - dsq01) / (2 * c0.r * dc01); if (cosMax > 1 && cosMax < 1 + 1e-9) { cosMax = 1; } this.angleMax = cosMax < -1 ? Math.PI : Math.acos(cosMax); double dc01r1 = dc01 + c1.r; double cosMin = c0.r == 0 ? 0 : (c0.r * c0.r + dc01r1 * dc01r1 - dsq01) / (2 * c0.r * dc01r1); if (cosMin < -1 && cosMin > -1 - 1e-9) { cosMin = -1; } this.angleMin = cosMin > 1 ? 0 : Math.acos(cosMin); for (int caseN = 0; caseN < 4; ++caseN) { result = solveWithSigns((caseN & 1) * 2 - 1, (caseN & 2) - 1); if (result != null) { break; } } } // Runs ternary search on multiple parts of the angle segment // with the given Y-signs in virtual coordinates wrt of c0 and c1 private Point[] solveWithSigns(int sign0, int sign1) { Point[] target = new Point[3]; final int nSteps = 20; double stepSize = (angleMax - angleMin) / nSteps; for (int step = 0; step < nSteps; ++step) { double left = angleMin + stepSize * step; double right = angleMin + stepSize * (step + 1); for (int iteration = 0; left < right && iteration < 50; ++iteration) { double ll = (left * 2 + right) / 3; double rr = (left + 2 * right) / 3; double lv = distanceTo2nd(sign0, sign1, ll, target); if (lv <= 1e-9) return target; double rv = distanceTo2nd(sign0, sign1, rr, target); if (rv <= 1e-9) return target; if (lv < rv) { right = rr; } else { left = ll; } } double center = (left + right) / 2; if (distanceTo2nd(sign0, sign1, center, target) <= 1e-9) { return target; } } return null; } private double distanceTo2nd(int sign0, int sign1, double angle, Point[] target) { // Find where the first point will be target[0] = c0.c.add(c0c1n.rotate(Math.cos(angle), Math.sin(angle * sign0))); // then we intersect circles c1 and (c = target[0], r = d01) Vector t0c1 = target[0].vectorTo(c1.c); double t0c1l2 = t0c1.len2(); double xn = (t0c1l2 - c1.r * c1.r + dsq01) / (2 * t0c1l2); double yn = sign1 * Math.sqrt(Math.max(0, dsq01 / t0c1l2 - xn * xn)); Vector t0t1 = t0c1.scale2d(xn, yn); target[1] = target[0].add(t0t1); // then we find the remaining point by rotating and scaling the difference between those two target[2] = target[0].add(t0t1.scale2d(scale2fwd, scale2ort)); // not exactly the distance, but monotonicity is OK, and cheap enough return target[2].dist2(c2.c) - c2.r * c2.r; } } // Produce a solution by matching given circles in order, or return null static Point[] directMatch(Circle s0, Circle s1, Circle s2, Circle p0, Circle p1, Circle p2) { if (s0.r < p0.r || s1.r < p1.r || s2.r < p2.r) { return null; } // Transition into circles and a triangle Circle c0 = new Circle(s0.c, s0.r - p0.r); Circle c1 = new Circle(s1.c, s1.r - p1.r); Circle c2 = new Circle(s2.c, s2.r - p2.r); double dsq01 = p0.c.dist2(p1.c); double dsq02 = p0.c.dist2(p2.c); double dsq12 = p1.c.dist2(p2.c); // Determine the orientation of the triangle p0p1p2 double signum = Math.signum(p0.c.vectorTo(p1.c).crossProduct(p0.c.vectorTo(p2.c))); // Validate very easy constraints double d01 = Math.sqrt(dsq01); double d02 = Math.sqrt(dsq02); double d12 = Math.sqrt(dsq12); double dc01 = Math.sqrt(c0.c.dist2(c1.c)); double dc02 = Math.sqrt(c0.c.dist2(c2.c)); double dc12 = Math.sqrt(c1.c.dist2(c2.c)); if (d01 > 1e-9 + dc01 + c0.r + c1.r || d01 + 1e-9 < dc01 - c0.r - c1.r || d02 > 1e-9 + dc02 + c0.r + c2.r || d02 + 1e-9 < dc02 - c0.r - c2.r || d12 > 1e-9 + dc12 + c1.r + c2.r || d12 + 1e-9 < dc12 - c1.r - c2.r) { return null; } // Try solving with three different matches being on borders Point[] match; if ((match = triangleBoundaryMatch(c0, c1, c2, dsq01, dsq02, dsq12, +signum)) != null) { return match; } if ((match = triangleBoundaryMatch(c0, c2, c1, dsq02, dsq01, dsq12, -signum)) != null) { Point tmp = match[1]; match[1] = match[2]; match[2] = tmp; return match; } if ((match = triangleBoundaryMatch(c2, c1, c0, dsq12, dsq02, dsq01, -signum)) != null) { Point tmp = match[0]; match[0] = match[2]; match[2] = tmp; return match; } return null; } // An algorithmic entry, also used for stress testing public static String match(int[] rawInput) { int gIdx = 0; Circle[] plug = new Circle[3]; for (int i = 0; i < 3; ++i) { plug[i] = new Circle(new Point(rawInput[gIdx++], rawInput[gIdx++]), rawInput[gIdx++]); } Circle[] socket = new Circle[3]; for (int i = 0; i < 3; ++i) { socket[i] = new Circle(new Point(rawInput[gIdx++], rawInput[gIdx++]), rawInput[gIdx++]); } // Try two orientations and direct circle match for (int orientation = 0; orientation <= 3; orientation += 3) { Point[] s = directMatch(socket[0], socket[1], socket[2], plug[0], plug[1 ^ orientation], plug[2 ^ orientation]); if (s != null) { return s[0].x + " " + s[0].y + "\n" + s[1 ^ orientation].x + " " + s[1 ^ orientation].y + "\n" + s[2 ^ orientation].x + " " + s[2 ^ orientation].y + "\n"; } } return null; } public static void main(String[] args) throws IOException { try (BufferedReader in = new BufferedReader(new InputStreamReader(System.in)); PrintWriter out = new PrintWriter(System.out)) { // Read input int[] rawInput = new int[18]; for (int i = 0, t = 0; i < 6; ++i) { StringTokenizer st = new StringTokenizer(in.readLine()); for (int j = 0; j < 3; ++j, ++t) { rawInput[t] = Integer.parseInt(st.nextToken()); } } // Solve the problem and print the answer String solution = match(rawInput); if (solution == null) { out.println("NO"); } else { out.println("YES"); out.print(solution); } } } }