Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Extend line to smoothly connect with another line

I have two curves that look like this:

fig1

I'm looking for a way to smoothly connect the blue curve with the red one by extending the former (blue line) upwards and to the right, while leaving the latter (red line) untouched. The direction is important, I mention this because it looks as if it would be easier to continue the blue line to the left. I can't do this (it wouldn't make sense in my larger code) so it has to be upwards and to the right.

Here's what I've managed to do so far (the section where the two lines get close is zoomed in):

fig2

Basically I'm interpolating a new curve using a sample of points from both curves (the black dots) The MWE code to obtain this plot is below.

What I need to do now is find a way to trim the green line from the point where it meets the red line to the point where it meets the blue line and extend the blue line replacing the little last segment that is now no longer necessary.

This is how the blue line should look after the changes above are applied (made by hand):

fig3

where the trimmed section of the green line is now a part of the blue line. Notice that I have:

  1. discarded the extra points of the green line that extend beyond the intersection with the red line
  2. discarded the extra points of the green line that extend beyond the intersection with the blue line.
  3. attached the remaining section of the green line to the blue line after discarding the portion of the blue line that extended to the left beyond the intersection of the green and blue lines.

Since I already have the interpolating curve (the green line), all I need is a way to:

  1. Trim it up to the points where it intersects the other two curves as explained above.
  2. Replace the last portion of the blue line with this trimmed portion of the new interpolated line.

In this particular example I've used fixed lists to plot and perform the calculations, but I have several pairs of lines for which I need to perform a similar operation, so the solution would have to be general enough to contemplate cases with similarly shaped but different curves. How could I do this?

I'm open to solutions making use of numpy, scipy or whatever is necessary.

Here's the MWE:

import numpy as np
import matplotlib.pyplot as plt

# Red line data.
x1 = [0.01, 0.04, 0.08, 0.11, 0.15, 0.18, 0.22, 0.25, 0.29, 0.32, 0.35, 0.38, 0.41, 0.44, 0.46, 0.49, 0.51, 0.54, 0.56, 0.58]
y1 = [2.04, 2.14, 2.24, 2.34, 2.44, 2.54, 2.64, 2.74, 2.84, 2.94, 3.04, 3.14, 3.24, 3.34, 3.44, 3.54, 3.64, 3.74, 3.84, 3.94]

# Blue line data.
x2 = [0.4634, 0.4497, 0.4375, 0.4268, 0.4175, 0.4095, 0.4027, 0.3971, 0.3925, 0.389, 0.3865, 0.3848, 0.384, 0.3839, 0.3845, 0.3857, 0.3874, 0.3896, 0.3922, 0.3951, 0.3982, 0.4016, 0.405, 0.4085, 0.412, 0.4154, 0.4186, 0.4215, 0.4242, 0.4265, 0.4283, 0.4297, 0.4304, 0.4305, 0.4298, 0.4284, 0.4261, 0.4228, 0.4185, 0.4132, 0.4067, 0.399, 0.39, 0.3796, 0.3679, 0.3546, 0.3397, 0.3232, 0.305, 0.285]
y2 = [1.0252, 1.0593, 1.0934, 1.1275, 1.1616, 1.1957, 1.2298, 1.2639, 1.298, 1.3321, 1.3662, 1.4003, 1.4344, 1.4685, 1.5026, 1.5367, 1.5708, 1.6049, 1.639, 1.6731, 1.7072, 1.7413, 1.7754, 1.8095, 1.8436, 1.8776, 1.9117, 1.9458, 1.9799, 2.014, 2.0481, 2.0822, 2.1163, 2.1504, 2.1845, 2.2186, 2.2527, 2.2868, 2.3209, 2.355, 2.3891, 2.4232, 2.4573, 2.4914, 2.5255, 2.5596, 2.5937, 2.6278, 2.6619, 2.696]

x3, y3 = [], []

# Store a small section of the blue line in these new lists: only those points
# closer than 0.2 to the last point in this line.
for indx,y2_i in enumerate(y2):
    if (y2[-1]-y2_i)<=0.2:
        y3.append(y2_i)
        x3.append(x2[indx])

# The same as above but for the red line: store only those points between
# 0. and 0.4 in the y axis and with a larger x value than the last point in the
# blue line.
for indx,y1_i in enumerate(y1):
    if 0. <(y1_i-y2[-1])<=0.4 and x1[indx] > x2[-1]:
        y3.append(y1_i)
        x3.append(x1[indx])

# Find interpolating curve that joins both segments stored in x3,y3.
poli_order = 3 # Order of the polynome.
poli = np.polyfit(y3, x3, poli_order)
y_pol = np.linspace(min(y3), max(y3), 50)
p = np.poly1d(poli)
x_pol = [p(i) for i in y_pol]

plt.plot(x1,y1, 'r')
plt.plot(x2,y2, 'b')
plt.plot(x_pol,y_pol, 'g')
plt.scatter(x3,y3,c='k')

plt.show()
like image 962
Gabriel Avatar asked Dec 17 '13 20:12

Gabriel


People also ask

How to extend a line to an intersection with another line?

Extending a line to an intersection with another line 1 Click the Edit tool on the Editor toolbar. 2 Select the line segment to which you want to extend a line. 3 Click the Extend tool on the Advanced Editing toolbar. 4 Click the endpoint of the feature you want to extend.#N#The line you clicked is extended to the selected line. More ...

How do I use the extend tool to extend lines?

To use the Extend tool, select the feature that you want to extend lines to, then start clicking the lines you want to extend. Click the Edit tool on the Editor toolbar. Select the line segment to which you want to extend a line. Click the Extend tool on the Advanced Editing toolbar. Click the endpoint of the feature you want to extend.

How to extend two lines to each other with one action?

To extend and trim two lines to each other with one action, you can use ROUND with a radius of 0. (No arc will be generated) I just don't know any method to do this with thousands of lines at the same time. (Maybe with LISP, but this could be dependant on the selection order, if it will mess up the drawing, or not...i guess)

How do I extend a line in AutoCAD?

To use the Extend tool, select the feature that you want to extend lines to, then start clicking the lines you want to extend. Click the Edit tool on the Editor toolbar. Select the line segment to which you want to extend a line. Click the Extend tool on the Advanced Editing toolbar.


1 Answers

As others mentioned, try using a spline. Your smooth curve isn't so smooth in the derivative, going from the continuous line to the straight one looks like a discontinuity in f'(x). Because of that I tightened the bounds down to 0.2 from 0.4 which grabs only a single point for the fits of the red line. Without that the spline will over-interpolate around the extra red points.

A quick example using your defs. from above:

from scipy.interpolate import spline
sx = np.array(x2+x3)
sy = np.array(y2+y3)
t  = np.arange(sx.size,dtype=float)
t /= t[-1]
N  = np.linspace(0,1,2000)
SX = spline(t,sx,N,order=4)
SY = spline(t,sy,N,order=4)

plt.plot(x1,y1, 'r')
plt.plot(x2,y2, 'b')
plt.scatter(x3,y3,c='k')

plt.plot(SX, SY,'g',alpha=.7,lw=3)    
plt.show()

enter image description here

This question is a handy reference:

Smooth spline representation of an arbitrary contour, f(length) --> x,y

like image 166
Hooked Avatar answered Sep 30 '22 07:09

Hooked