/* * Aligned path objects * * Create a schematic street map from line and ring segments. The line segments * can have arbitrary length, the ring segments can have arbitrary radius and * angle. This is implemented with path objects. By using named points and * the "attachmentpoint" and "align" options the positioning of the segments * in a seamless fashion is very easy. * * Required software: PDFlib/PDFlib+PDI/PPS 9 * Required data: none */ package com.pdflib.cookbook.pdflib.path_objects; import com.pdflib.pdflib; import com.pdflib.PDFlibException; public class aligned_path_objects { /** * The basic unit in points. */ final static double BU = 20; /** * Size of the circle for the reference point. */ final static double REF_POINT_SIZE = BU / 20; /** * The page width */ final static double PG_WIDTH = 11 * BU; /** * The page height */ final static double PG_HEIGHT = 11 * BU; /** * The street width in basic units. */ final static double STREET_WIDTH = 0.15; /** * The pdflib object */ private pdflib p; private interface segment { public int create_path() throws PDFlibException; } private class ring_segment implements segment { ring_segment(double radius, double phi) { this.radius = radius; this.phi = phi; } /** * Create a path for a ring segment using polar coordinates. A positive * angle means a turn to the left, a negative angle means a turn to the * right. */ public int create_path() throws PDFlibException { double r1 = radius * BU; double r2 = (radius + STREET_WIDTH) * BU; double psi = 0; /* * Ring with phi > 0 is constructed in the first quadrant. * Ring with phi < 0 is constructed in the fourth quadrant: * Rotation through -180. */ if (phi < 0) { final double rad = r1; r1 = r2; r2 = rad; psi = -180; } int path = p.add_path_point(-1, r1, psi, "move", "polar name=pivot"); p.add_path_point(path, r1, psi + phi / 2, "control", "polar"); p.add_path_point(path, r1, psi + phi, "circular", "polar name=attach"); p.add_path_point(path, r2, psi + phi, "line", "polar name=dir"); p.add_path_point(path, r2, psi + phi / 2, "control", "polar"); p.add_path_point(path, r2, psi, "circular", "polar"); return path; } double radius; double phi; } private class line_segment implements segment { line_segment(double length) { this.length = length; } /** * Create a path for a line segment. */ public int create_path() throws PDFlibException { final double l = length * BU; final double w = STREET_WIDTH * BU; int path = p.add_path_point(-1, 0, 0, "move", "name=pivot"); p.add_path_point(path, 0, l, "line", "name=attach"); p.add_path_point(path, w, l, "line", "name=dir"); p.add_path_point(path, w, 0, "line", ""); return path; } double length; } private void run() { /* This is where the data files are. Adjust if necessary. */ final String searchpath = "../input"; final String outfile = "aligned_path_objects.pdf"; final String title = "Aligned path objects"; int exitcode = 0; try { p = new pdflib(); p.set_option("searchpath={" + searchpath + "}"); p.set_option("errorpolicy=exception"); if (p.begin_document(outfile, "") == -1) throw new Exception("Error: " + p.get_errmsg()); p.set_info("Creator", "PDFlib Cookbook"); p.set_info("Title", title); p.begin_page_ext(PG_WIDTH, PG_HEIGHT, ""); /* * Description */ String optlist = "fontname=Helvetica encoding=unicode " + "fontsize=" + BU / 2; p.fit_textline("Aligned path objects", 2 * BU, PG_HEIGHT - 2 * BU, optlist); final segment segments[] = { new line_segment(4.5), new ring_segment(0.5, -70), new line_segment(3.5), new ring_segment(0.2, -135), new line_segment(0.5), new ring_segment(0.1, 35), new ring_segment(7, 80), new ring_segment(0.1, -170), new line_segment(3), new ring_segment(0.5, -60), new line_segment(2.5), new ring_segment(0.1, 90), new ring_segment(1.2, 60), new ring_segment(0.3, -100), new line_segment(2.5), new ring_segment(0.3, -80), new line_segment(1.5), new ring_segment(0.15, 160), new line_segment(0.7), new ring_segment(0.15, 60), new ring_segment(0.15, -40), new line_segment(0.6), new ring_segment(0.15, -85), new line_segment(0.755), new ring_segment(0.15, -104), new line_segment(0.99), }; /* * Initial direction */ double dx = 0.469; double dy = 0.883; String align_opt = "align={" + dx + " " + dy + "}"; /* * Start point */ final double startx = 4.7 * BU; final double starty = 1 * BU; double x = startx; double y = starty; /* * Loop over segments and draw them one by one */ int i; int path; for (i = 0, path = -1; i < segments.length; i += 1) { if (path != -1) { /* * Compute the coordinates of the next pivot point */ final double xatt = p.info_path(path, "px", align_opt + " attachmentpoint=pivot name=attach"); final double yatt = p.info_path(path, "py", align_opt + " attachmentpoint=pivot name=attach"); /* * Compute the new alignment vector */ final double xdir = p.info_path(path, "px", align_opt + " attachmentpoint=pivot name=dir"); final double ydir = p.info_path(path, "py", align_opt + " attachmentpoint=pivot name=dir"); dx = xdir - xatt; dy = ydir - yatt; align_opt = "align={" + dx + " " + dy + "}"; /* * New reference vector */ x += xatt; y += yatt; /* * Get rid of previous path */ p.delete_path(path); } /* * Create the path object and draw the path, taking the "pivot" * point as attachment point and aligned to the alignment * vector. */ path = segments[i].create_path(); p.draw_path(path, x, y, align_opt + " fillcolor=white attachmentpoint=pivot " + "close stroke fill linewidth=0.5"); /* * Mark the pivot point */ p.setcolor("fill", "red", 0, 0, 0, 0); p.circle(x, y, REF_POINT_SIZE / 2); p.fill(); } /* * Delete last path object */ if (path != -1) { p.delete_path(path); } /* * Redraw the first pivot point on top */ p.setcolor("fill", "red", 0, 0, 0, 0); p.circle(startx, starty, REF_POINT_SIZE / 2); p.fill(); p.end_page_ext(""); p.end_document(""); } catch (PDFlibException e) { System.err.println("PDFlib exception occurred:"); System.err.println("[" + e.get_errnum() + "] " + e.get_apiname() + ": " + e.get_errmsg()); exitcode = 1; } catch (Exception e) { System.err.println(e); exitcode = 1; } finally { if (p != null) { p.delete(); } System.exit(exitcode); } } public static void main(String argv[]) { aligned_path_objects instance = new aligned_path_objects(); instance.run(); } }