Create offset line contours from a line set with arbitrary topology - graphics

Example image:
Given a set of connected lines (see thick black lines in example image), how can you generate a set of offset contour lines that form loops (see thin blue lines)? The offset is constant across all lines, and the contours are always parallel to its associated lines.
The input line topology is arbitrary: i.e. it may contain cycles. Note that the number of contour loops is equal to the number of cycles plus one. A solution that just deals with tree topologies only (no cycles) could also be of interest.
Any papers or relevant algorithms out there that tackle this problem?

The basic method is to construct the bissectrix of the angles (on the right side) and draw on it a length such that it achieves the desired offset (a little of trigonometry). And to link them in the loop traversal order. Different capping rules can be used at free endpoints.
For this to be possible, you need a representation of the geometry as a planar graph (quad-edge for instance). Maybe have a look here: https://mathoverflow.net/q/23811.
Anyway, this method will not avoid the overlaps that can arise, nor self-intersecting offsets. These are much more difficult problems that require a global approach, and are similar to the polygon union problem.

Related

Envelope of Lines

Its been a while that I'm stuck with an apparently "simple" problem. My goal is to build the envelope of a set of lines that are "attached" to a curve. Let's say a curve like this:
For the above example I would expect the envelope of lines (whose directions are depicted by arrows and are orthogonal to the edges of the red curve) to be an arc of a circle.
I thought of doing this in two computationally separate ways:
Intersection of consecutive lines: In an ideal smooth world, the envelop of lines attached is a curve where the red lines are all tangent to. Now, coming back to the discrete world I try to obtain the envelope curve by intersecting consecutive lines (for example the first line with the second line would give the first vertex of the envelope).
Evolute of the red curve: Again in an ideal smooth world, one can think of such an envelop as the evolute of the red curve (see Evolute - wikipedia). Therefore, all I had to do in addition to current info was to compute the curvature and then build the evolute (naturally I had to use a discrete version of curvature which you can find its definition here: Discrete Curvature - wikipedia).
Doing any of the above approaches I would get the following result:
However, finding the "correct arc" is heavily dependent on the accuracy of the initial data which is the red curve. As soon as the red curve has some "noises" in the vertices the envelope is heavily distorted. Here I add a picture (where the red curve is visually intact (but not actually) yet the envelope is distorted):
My Question: How can I rectify this? I believe there should be a numerical approach to solve this issue as I badly need this envelope to be correctly built. I'm a mathematician and am not fully aware of the numerical tricks that might exist in dealing with cases like this.
However, I believe that this should be a standard question in computer graphics community though I could not find anything properly relevant after searching for months.
It would be great if the solutions are in MATLAB language. Please let me know if you want me to be more accurate regarding the passage.
For the line intersecton method, yes, because the lines are relatively parallel, any small error in the defining data for a line will produce a dramatic error in their intersection points.
I suggest the following:
Calculate all lines.
Calculate all intersection points of the adjacent lines.
Calculate the distances between all adjacent intersection points.
Sequence plot the distances, and identify all distances which are more than,
perhaps, 2 standard deviations from the trend line of the distances.
If the data is not "too bad" then I think the identified distances
will mostly come in pairs, ie, there is one "bad" intersection line
causing two "bad" distances.
Exclude the "bad" lines and reprocess the remaining intersection points.
The above assumes the granularity of the data is greater where the base curve is curvier.
If the intersection point distances seem to form two trend lines, especially if they look like to two diverging, or two converging, trend lines, then group the intersection lines accordingly, plot two envelopes, and take the average of the two envelopes as "the envelope". (Or perahps even more trend lines, if there is a regular error in the data.)
But, if there are signs of regular data errors, then a contextual assessment and analysis of the data source and how it was generated/gathered/measured might be required to correctly determine which data should be excluded.

How to identify joints in the profile of a shape?

I'm working on a system to automatically take 2D profiles of components and assemble them into 3D shapes.
Imagine given these pieces:
You want to make this shape:
I'm highlighting one of the components to show how they fit together.
I'm open to any suggestions on how to go about doing this but the current approach I'm attempting first finds joints that may fit together just by looking at the 2D profile.
How could I go about identifying the "tabs" from the polyline profile?
The same technique should also work on assemblies like such:
see How to compare two shapes?
so you basically trying to find the "same" sequences in polylines encoded in the polar increment format (turn angle, line length) and then just check if relative position of matched sequences are the same in both shapes ...
Beware that the locks might have some gap between the joined shapes to ensure assembly is possible... in same case the gap might be even negative (overlap) depends on material and function so You need to compare the sequences with some margin ...
Also I would divide each shape into its sides to speed up the process as the lock is most likely not crossing sides ...
You may define the "code" for a tab. For example:
3,C,5,C,3 would mean: Three units length, then turn 90º counter-clockwise, then 5 units length, then turn 90º counter-clockwise, then 3 units length.
Of course more identifiers than C can be used, for different angles and so.
A tab in another piece that fits in the tab of the first piece has the same (or very similar) 3,C,5,C,3 code
So, finding same code in both pieces may be a fit. Check if adjacents codes in both pieces also fit, and you're done.
Notice that pieces can be rotated. This case doesn't change the code, but may change the order of adjacents codes.

Fitting multiple curves to one data set

I have a data set that I receive from an outside source, and have no real control over.
The data, when plotted, shows two clumps of points with several sparse, irrelevant points. Here is a sample plot:
There is a clump of points on the left, clustered around (1, 16). This clump is actually part of a set of points that lies on (or near to) a line stretching from (1, 17.5) to (2.4, 13).
There is also an apparent curve from (1.75, 18) to (2.75, 12.5).
Finally, there are some sparse points above the second curve, around (2.5, 17).
Visually, it's not difficult to separate these groups of points. However, I need to separate these points within the data file into three groups, which I'll call Line, Curve, and Other (the Curve group is the one I actually need). I'd like to write a program that can do this reasonably well without needing to visually see the plot.
Now, I'm going to add a couple items that make this much worse. This is only a sample set of data. While the shapes of the curve and line are relatively constant from one data set to the next, the positions are not. These regions can (and do) shift, both horizontally and vertically. The only real constant is that there's a negative-slope line from the top-left to the bottom-right of the plot, an almost curve from the top-center to the bottom-right, and most of the sparse points are in the top-right corner, above the curve.
I'm on Linux, and I'm out of ideas. I can tell you the approaches that I've tried, though they have not done well.
First, I cleaned up the data set and sorted it in ascending order by x-coordinate. I thought that maybe the points were sorted in some sort of a logical way that would allow me to 'head' or 'tail' the data to achieve the desired result, but this was not the case.
I can write a code in anything (Python, Fortran, C, etc.) that removes a point if it's not within X distance of the previous point. This would be just fine, except that the scattering of the points is such that two points very near each other in x, are separated by an appreciable distance in y. It also doesn't help that the Line and Curve draw near one another for larger x-values.
I can fit a curve to a partial data set. When I sort the data by x-coordinate, for example, I can choose to only plot the first 30 points, or the last 200, or some set of 40 in the middle somewhere. That's not a problem. But the Line points tuck underneath the Curve points, which causes a problem.
If the Line points were fairly constant (which they're not), I could rotate my plot by some angle so that the Line is vertical and I can just look at the points to the right of that line, then rotate back. This may the best way to go about doing this, but in order to do that, I need to be able to isolate the linear points, which is more or less the essence of the problem.
The other idea that seems plausible to me, is to try to identify point density and split the data into separate files by those parameters. I think this is the best candidate for this problem, since it is independent of point location. However, I'm not sure how to go about doing this, especially because the Line and Curve do come quite close together for larger x-values (In the sample plot, it's x-values greater than about 2).
I know this does not exactly fall in with the request of a MWE, but I don't know how I'd go about providing a more classical MWE. If there's something else I can provide that would help, please ask. Thank you in advance.

Breaking a path into 100 pixel lines

I have a path drawn in Illustrator, and I need to break the path into section of 100 px. I can't figure out the logic. A line consist of 2 points x1,y1 and x2, y2. And this is for a straight line. My line may have angles/curve, so what do I need to do, to figure out the distance between 2 pixels.Here is a graphic illustration of my line and the sections, which I need to select/extract:
From the shape above, I need to break it into section of lines(note these are not straight lines).
Try referencing the Bug Algorithm. It's a very simple intuitive approach to path planning. I've uploaded an example written in LabVIEW here, but I know there are plenty of others available.
The Bug Algorithm generates a continuous line; a lot of data points; however you can keep a running average of the general diretion it's heading in and detect sharp changes in angles as an important node in the path. This allows you to segment paths from possibly thousands of data points into just a handful.
There are two aspects in your question:
how do I break a path at some point,
how do I find points spaced by a certain distance.
To answer the first, the type of primitives that define the path matters. Assuming a sequence of Bezier cubics, you will resort to the de Casteljau's algorithm: it allows you to construct the control points that correspond to a desired section of a given Bezier arc, from the original control points. Then, a section of a path will be obtained as a starting section of an initial Bezier, then (possibly) a sequence of whole Bezier arcs, and finally the ending section of a last Bezier arc.
To answer the second, assuming that you need an accurate answer, you will need to resort to numerical integration of the arc length along the path. Refer to this post: https://math.stackexchange.com/a/1171564/65203.
For a simple approximation, you can flatten the curve (approximate it as a polyline) and compute the accumulated segment lengths (or even count the pixels if your curve renderer gives you access to this information).
This process is not trivial.

Looking for a fast polygon rendering algorithm

I am working with a Microchip dsPIC33FJ128GP802. It's a small DSP-based microcontroller, and it doesn't have much power (40 million instructions per second). I'm looking for a way to render a convex (i.e. simple) polygon. I am only dealing with 2D shapes, integer math, and set or clear pixels (i.e. 1 bit per pixel.) I already have routines for drawing fast horizontal and vertical lines (writing up to 16 pixels in 88 cycles), so I would like to use a scanline algorithm.
However, all the algorithms I have found seem to depend on division (which takes 18 cycles on this processor) and floating point math (which is emulated in software and so is very slow; it also takes up a lot of ROM), or assume that I have a large amount of memory. I only have 2K left, ~14K is used for graphics RAM of my 16K. So does anyone know of any good, embedded machine algorithms they can point me to with a simple C or pseudocode implementation which I can implement in assembly? Preferably on the 'net, I don't live near any good bookstores with many programming books.
Thanks. :)
EDIT: Clarification, this is a polygon filling algorithm I'm looking for. I can implement a polygon outline algorithm using Bresenham's line drawing algorithm (as Marc B suggests.)
EDIT #2: I wanted to let everyone know I got a basic algorithm up in Python. Here's a link to the code. Public domain code.
http://dl.dropbox.com/u/1134084/bresenham_demos.py
How about Bresenham's Line algorithm? After some setup, it's pure integer math, and can be adapted to draw a polygon by simple iteration of starting points along the polygon edges.
comments followup:
I'll try to draw this in ASCII, but it'll probably look like crud. Bresenham's can be used to draw a filled polygon by picking a starting edge, and iteratively moving a bresenham line across the canvas parallel to that point.
Let's say you've got some points like this:
*(1)
*(3)
*(2)
*(4)
These are numbered in left-right sort priority, so you pick the left-most starting point (1) and decide if you want to go vertically (start 1,2) or horizontally (1,3). That'd probably depend on how your DSP does its display, but let's go with vertical.
So... You use the 1-2 line as your starting bresenham line. You calculate the starting points of your fill lines by using lines 1-3 and 2-4 as your start/end points. Start a bresenham calculation for each, and draw another Bresenham between those two points. Kinda like:
1.1 -> 2.1, then 1.2 -> 2.2, then 1.3 -> 2.3
etc... until you reach the end of either of those lines. In this case, that'd be when the lower starting point reaches (4). At that point, you start iterating up the 4,3 line, until you reach point 3 with both starting points, and you're done.
*-------
\\\\\\\\ *
\\\\\\\\
*-----\\
------- *
Where the dashes are the starting points you calculated along 1-3 and 2-4, and the slashes are the fill lines.
Of course, this only works if the points are properly sorted, and you've got a convex polygon. If it's concave, you'll have to be very careful to not let your fill lines cross over the border, or do some pre-processing and subdivide the original poly into two or more convex ones.
You may want to look at Michael Abrash's articles on Dr Dobbs about polygon fill/raster/etc. It uses fixed-point math
Thomas, if you have a Bresenham line drawing algorithm available, then use it as a basis for further enhancement: divide your polygon to sub-polygons with an horizontal cutting line through every vertex. Then, start tracing the 2 left and right sides of each of these sub-polys, using Bresenham. This way you have the 2 end-points of each scan line in your polygon.
I would start by converting the polygon to a collection of triangles and render those, because triangles are easy to render by scanlines. Although even so there are some details.
Essentially, the draw-triangle sub-procedure will be given a raw triangle and proceed:
Reject degenerate triangles (where two of the three vertices overlap).
Sort the vertices in Y (since there are only three you can hardcode the sorting logic).
Now, at this point you should know that there will be three kinds of triangles: ones with a flat top, ones with a flat bottom, and "general" triangles. You want to handle a general triangle by essentially splitting it into one each of the flat types. This is because you don't want to have an if test every scanline to detect if the slope changed.
To render a flat triangle, you would run two Bresenham algorithms in parallel to iterate the pixels comprising the edges, and use the points they give you as the endpoints of each horizontal scanline.
It may be easier to break the problem into two parts. First, locate/write an algorithm that draws and fills a triangle. Second, write an algorithm that breaks up an arbitrary polygon into triangles (using different combinations of the vertices).
To draw/fill a triangle, use Bresenham's Line Algorithm to simultaneously draw a line between points 0 and 1, and between 1 and 2. For each input point x, draw the pixel if it is equal to or in between the y points generated by the two lines. When you reach one endpoint, continue by using the unfinished side and the side that has not yet been used.
Edit:
To break your convex polygon into triangles, arrange the points in order and call them P1, P2, ... PN. Let P1 be your "root" point, and build triangles using that point and combinations of adjacent points. For example, a pentagon would yield the three triangles P1-P2-P3, P1-P3-P4, and P1-P4-P5. In general, a convex polygon with N sides will decompose into N-2 triangles.

Resources