Issue
I want to draw Bézier curves on JupyterLab with Python, and I am using MatplotLib in order to make a replica of a Lamborghini. The drawing has to be a faithful replica, so I used NumPy to bring the Lamborghini image as a background, as long as I can draw over it and manipulate its properties such as opacity. But no matter what I do, these very first points of the bumber just go crazy. I tried using Path.CURVE3 and Path.CURVE4, Path.STOP and also Path.LINETO in order to make the Bézier curve stop properly on a given point (curve going crazy). I also tried making smaller curves, but I am not able to see what I want. I have to follow exactly the curves of the car. I used GIMP to extract the points I need.
Here is my code, actually, this situation is even more common than what I exposed here, it happens without NumPy image processing too. What are the rules of using CURVE objects? What are the limitations? What can make my curves go wrongly crazy?
import math
import matplotlib.patches as mpatches
import matplotlib.path as mpath
import matplotlib.pyplot as plt
import numpy as np
Path = mpath.Path
fig, ax = plt.subplots()
bumper = mpatches.PathPatch(
Path(
[(22, 163), (12, 134), (13, 132), (30.6, 117.65), (43, 118)],
[Path.MOVETO, Path.CURVE4, Path.CURVE4, Path.CURVE4, Path.CURVE4],
),
fc="none",
transform=ax.transData,
color="green",
lw=1,
)
ax.add_patch(bumper)
ax.set_title("Lamborghini Sián FKP 37", fontfamily="Tahoma", fontsize=22)
ax.set_aspect(1)
plt.xticks(np.linspace(0, 1180, 21), fontsize=10)
plt.yticks(np.linspace(0, 330, 9), fontsize=10)
plt.grid(color="gray", ls=":", lw=0.2)
lambo = plt.imread("Lamborghini Sian FKP 37 Right Side.png")
plt.imshow(lambo, alpha=0.35, extent=[0, 1180, 0, 330])
plt.rcParams["figure.figsize"] = (15, 6)
plt.show()
Solution
Research and documentation
So, after a period of research, I found this in MatplotLib's documentation. Which made me figure out the meaning of quadratic CURVE3
and cubic CURVE4
curves from `Path.
CURVE3
means you can only plot a curve with 2 given points, and CURVE4
with 3 points. We have to keep in mind that:
Start Point is like putting the pencil on the paper, the very first point that begins a new trajectory. You achieve this by starting with Path.MOVETO
;
Control Point is what really makes the curve. You can think of a perfectly straight rope between 2 given points. When the rope is pulled in some direction, it bends the rope creating the curve;
End Point is the very last point where you stop drawing and take the pencil off the paper.
How to use CURVE
attributes:
Path.CURVE3
must be used with exactly 2 points:
- 1 Control Point;
- 1 End Point.
Path.CURVE4
must be used with exact 3 points:
- 2 Control Points;
- 1 End Point.
I was struggling in a situation similar to this one:
# I had to put a lot of points in a `verts` list like this
verts = [(x,y), (x,y), (x,y), (x,y), (x,y)]
# Following the previous path structure, I got a `codes` list like this
codes = [Path.MOVETO, Path.CURVE4, Path.CURVE4, Path.CURVE4, Path.CURVE4]
Note that in this example we have 5 points. When we are going to plot Bézier curves, we have to analyze whether it has to be a quadratic CURVE3
or cubic CURVE4
curve.
If you have 4 points, use CURVE4
, if 3 use CURVE3
. It is up to you on how you are going to organize a bigger figure in subdivided curves, you may compose a plot from various different curves.
If you have more than the limit of points, you have to restart the path regarding the size of the curve. Like this:
verts = [(5, 30), (15, 55), (25, 15), (35, 40), # 4 points
(20, 10), (30, 0), (35, 10)], # 3 new points, start a new curve
# `codes` means: the instructions used to guide the line through the points
codes = [Path.MOVETO, Path.CURVE4, Path.CURVE4, Path.CURVE4, # Begin the curve
Path.MOVETO, Path.CURVE3, Path.CURVE3] # Start a new one
bezier1 = mpatches.PathPatch(
Path(verts, codes),
# You can also tweak your line properties, like its color, width, etc.
fc="none", transform=ax.transData, color="green", lw=2)
IMPORTANT: In addition, if you are plotting a single long curve, when a part of the line is completed, you have to start the continuation of the line by the immediate last point, this will give you a continuous. That is what I discovered, I hope this can help someone.
Answered By - NickS1
0 comments:
Post a Comment
Note: Only a member of this blog may post a comment.