線は長さを持ち、リングは半径と角度を持ちます。これをパスオブジェクトを使って実装します。名前付けされた点と attachmentpoint および align オプションを使うことによって、継ぎ目のないセグメントの位置づけを簡単に行えます。
/*
* $Id: aligned_path_objects.java,v 1.9 2013/01/15 10:11:59 stm Exp $
*
* 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
*/
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";
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 + " $Revision: 1.9 $");
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.print("PDFlib exception occurred:\n");
System.err.print("[" + e.get_errnum() + "] " + e.get_apiname()
+ ": " + e.get_errmsg() + "\n");
}
catch (Exception e) {
System.err.println(e.getMessage());
}
finally {
if (p != null) {
p.delete();
}
}
}
public static void main(String argv[]) {
aligned_path_objects instance = new aligned_path_objects();
instance.run();
}
}