{"id":477,"date":"2010-05-16T10:33:00","date_gmt":"2010-05-16T16:33:00","guid":{"rendered":"http:\/\/www.ourada.org\/blog\/?p=477"},"modified":"2010-05-16T10:33:00","modified_gmt":"2010-05-16T16:33:00","slug":"offsetting-a-polyline","status":"publish","type":"post","link":"https:\/\/www.ourada.org\/blog\/archives\/477","title":{"rendered":"Offsetting a polyline"},"content":{"rendered":"<p>Thanks to <a href=\"http:\/\/stackoverflow.com\/questions\/2824640\/generate-a-polygon-from-line\/2841459\">a question on StackOverflow<\/a>, I did some playing with Java&#8217;s Graphics2D. Below is some code to generate an offset of a polyline, i.e. given a polyline (a string of connected line segments), generate a polygon that represents a thick version of that line.<\/p>\n<p>Clearly, the Java guys took some shortcuts here, because the polygon ends up including a lot of interior segments that you don&#8217;t really want, etc. However, filling it using a nonzero winding rule covers a lot of sins. And I can understand why they committed those sins, since it&#8217;s kinda hard to do in general. Read the <a href=\"http:\/\/www.cgal.org\/Manual\/last\/doc_html\/cgal_manual\/Straight_skeleton_2\/Chapter_main.html\">CGAL page about offsetting<\/a> for an intro. Sometime I&#8217;ll have to investigate the shortcut methods in the OpenJDK source; looking at this output, I&#8217;m definitely curious.<\/p>\n<p><figure style=\"width: 228px\" class=\"wp-caption alignnone\"><img loading=\"lazy\" decoding=\"async\" alt=\"Unfilled\" src=\"http:\/\/www.ourada.org\/stackoverflow\/unfilled.png\" title=\"Unfilled\" width=\"228\" height=\"354\" \/><figcaption class=\"wp-caption-text\">Unfilled<\/figcaption><\/figure>  <figure style=\"width: 241px\" class=\"wp-caption alignnone\"><img loading=\"lazy\" decoding=\"async\" alt=\"Filled\" src=\"http:\/\/www.ourada.org\/stackoverflow\/filled.png\" title=\"Filled\" width=\"241\" height=\"365\" \/><figcaption class=\"wp-caption-text\">Filled<\/figcaption><\/figure><\/p>\n<pre>import java.awt.BasicStroke;\nimport java.awt.Shape;\nimport java.awt.geom.Path2D;\nimport java.awt.geom.PathIterator;\n\npublic class StrokePath\n{\n    public static void main(String[] args)\n    {\n        \/\/ set line width to 6, use bevel for line joins\n        BasicStroke bs = new BasicStroke(6.0f, BasicStroke.CAP_SQUARE, BasicStroke.JOIN_BEVEL);\n\n        \/\/ create a path for the input\n        Path2D p = new Path2D.Float();\n        p.moveTo(50.0, 50.0);\n        p.lineTo(65.0, 100.0);\n        p.lineTo(70.0, 60.0);\n        p.lineTo(120.0, 65.0);\n        p.lineTo(40.0, 200.0);\n\n        \/\/ create outline of wide lines by stroking the path with the stroke\n        Shape s = bs.createStrokedShape(p);\n        \/\/ output each of the segments of the stroked path for the output polygon\n        PathIterator pi = s.getPathIterator(null);\n        while (!pi.isDone())\n        {\n            pi.next();\n            double[] coords = new double[6];\n            int type = pi.currentSegment(coords);\n            switch (type)\n            {\n            case PathIterator.SEG_LINETO:\n                System.out.println(String.format(\"SEG_LINETO %f,%f\", coords[0], coords[1]));\n                break;\n            case PathIterator.SEG_CLOSE:\n                System.out.println(\"SEG_CLOSE\");\n                break;\n            case PathIterator.SEG_MOVETO:\n                System.out.println(String.format(\"SEG_MOVETO %f,%f\", coords[0], coords[1]));\n                break;\n            default:\n                System.out.println(\"*** More complicated than LINETO... Maybe should use FlatteningPathIterator? ***\");\n                break;\n            }\n        }\n    }\n}\n<\/pre>\n","protected":false},"excerpt":{"rendered":"<p>Thanks to a question on StackOverflow, I did some playing with Java&#8217;s Graphics2D. Below is some code to generate an offset of a polyline, i.e. given a polyline (a string of connected line segments), generate a polygon that represents a thick version of that line. Clearly, the Java guys took some shortcuts here, because the [&hellip;]<\/p>\n","protected":false},"author":1,"featured_media":0,"comment_status":"open","ping_status":"open","sticky":false,"template":"","format":"standard","meta":{"footnotes":""},"categories":[3],"tags":[],"class_list":["post-477","post","type-post","status-publish","format-standard","hentry","category-general","author-admin"],"_links":{"self":[{"href":"https:\/\/www.ourada.org\/blog\/wp-json\/wp\/v2\/posts\/477","targetHints":{"allow":["GET"]}}],"collection":[{"href":"https:\/\/www.ourada.org\/blog\/wp-json\/wp\/v2\/posts"}],"about":[{"href":"https:\/\/www.ourada.org\/blog\/wp-json\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"https:\/\/www.ourada.org\/blog\/wp-json\/wp\/v2\/users\/1"}],"replies":[{"embeddable":true,"href":"https:\/\/www.ourada.org\/blog\/wp-json\/wp\/v2\/comments?post=477"}],"version-history":[{"count":0,"href":"https:\/\/www.ourada.org\/blog\/wp-json\/wp\/v2\/posts\/477\/revisions"}],"wp:attachment":[{"href":"https:\/\/www.ourada.org\/blog\/wp-json\/wp\/v2\/media?parent=477"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/www.ourada.org\/blog\/wp-json\/wp\/v2\/categories?post=477"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/www.ourada.org\/blog\/wp-json\/wp\/v2\/tags?post=477"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}