How to draw smooth quad mesh with Processing? - graphics

I am trying to draw a mesh composed of several squares using splines in Processing, so far I have tried it
mesh = (
[100, 100],[150, 100],[200, 100],[250, 100],[300, 100],[350, 100],[400, 100],[450, 100],[500, 100],
[100, 150],[150, 150],[200, 150],[250, 150],[300, 150],[350, 150],[400, 150],[450, 150],[500, 150],
[100, 200],[150, 200],[200, 200],[250, 200],[300, 200],[350, 200],[400, 200],[450, 200],[500, 200],
[100, 250],[150, 250],[200, 250],[250, 250],[300, 250],[350, 250],[400, 250],[450, 250],[500, 250],
[100, 300],[150, 300],[200, 300],[250, 300],[300, 300],[350, 300],[400, 300],[450, 300],[500, 300],
[100, 350],[150, 350],[200, 350],[250, 350],[300, 350],[350, 350],[400, 350],[450, 350],[500, 350],
)
def draw():
clear()
background(255)
stroke(0)
strokeWeight(1.2)
beginShape()
for p in mesh:
curveVertex(*p)
endShape()
stroke(*POINT_COLOR)
strokeWeight(POINT_RADIUS)
for p in mesh:
point(*p)
where mesh is the matrix of all vertices. I want to draw all 4 edges of all squares, how can I do it using splines? Later I will allow users to drag vertices to change mesh shape and I want that shape to be smooth. The final result would be something like below but on 2D plane:

Here's my recommendation (disclaimer: I don't use processing in python, so I couldn't test run this code and there may be errors):
mesh = (
[[100, 100],[150, 100],[200, 100],[250, 100],[300, 100],[350, 100],[400, 100],[450, 100],[500, 100]],
[[100, 150],[150, 150],[200, 150],[250, 150],[300, 150],[350, 150],[400, 150],[450, 150],[500, 150]],
[[100, 200],[150, 200],[200, 200],[250, 200],[300, 200],[350, 200],[400, 200],[450, 200],[500, 200]],
[[100, 250],[150, 250],[200, 250],[250, 250],[300, 250],[350, 250],[400, 250],[450, 250],[500, 250]],
[[100, 300],[150, 300],[200, 300],[250, 300],[300, 300],[350, 300],[400, 300],[450, 300],[500, 300]],
[[100, 350],[150, 350],[200, 350],[250, 350],[300, 350],[350, 350],[400, 350],[450, 350],[500, 350]]
)
def draw():
background(255)
stroke(0)
for i in range(len(mesh)):
beginShape()
curveVertex(mesh[i][0][0], mesh[i][0][0])
for j in range(len(mesh[i])):
curveVertex(mesh[i][j][0], mesh[i][j][0])
curveVertex(mesh[i][len(mesh[i]) - 1][0], mesh[i][len(mesh[i]) - 1][0])
endShape()
for i in range(len(mesh[0])):
beginShape()
curveVertex(mesh[0][i][0], mesh[0][i][1])
for j in range(len(mesh)):
curveVertex(mesh[j][i][0], mesh[j][i][0])
curveVertex(mesh[len(mesh) - 1][i][0], mesh[len(mesh) - 1][i][1])
endShape()
This draws a line across each row, then a line down each column (at least, that was my intent). Note that I made each row its own list, as opposed to having all the coordinate pairs in a single tuple. This allowed me to iterate through the points in a much more organized manner.

Related

Image intensity distribution changes during opencv warp affine

I am using python 3.8.5 and opencv 4.5.1 on windows 7
I am using the following code to rotate images.
def pad_rotate(image, ang, pad, pad_value=0):
(h, w) = image.shape[:2]
#create larger image and paste original image at the center.
# this is done to avoid any cropping during rotation
nH, nW = h + 2*pad, w + 2*pad #new height and width
cY, cX = nW//2, nH//2 #center of the new image
#create new image with pad_values
newImg = np.zeros((h+2*pad, w+2*pad), dtype=image.dtype)
newImg[:,:] = pad_value
#paste new image at the center
newImg[pad:pad+h, pad:pad+w] = image
#rotate CCW (for positive angles)
M = cv2.getRotationMatrix2D(center=(cX, cY), angle=ang, scale=1.0)
rotImg = cv2.warpAffine(newImg, M, (nW, nH), cv2.INTER_CUBIC,
borderMode=cv2.BORDER_CONSTANT, borderValue=pad_value)
return rotImg
My issue is that after the rotation, image intensity distribution is different than original.
Following part of the question is edited to clarify the issue
img = np.random.rand(500,500)
Rimg = pad_rotate(img, 15, 300, np.nan)
Here is what these images look like:
Their intensities have clearly shifted:
np.percentile(img, [20, 50, 80])
# prints array([0.20061218, 0.50015415, 0.79989986])
np.nanpercentile(Rimg, [20, 50, 80])
# prints array([0.32420028, 0.50031483, 0.67656537])
Can someone please tell me how to avoid this normalization?
The averaging effect of the interpolation changes the distribution...
Note:
There is a mistake in your code sample (not related to the percentiles).
The 4'th argument of warpAffine is dst.
replace cv2.warpAffine(newImg, M, (nW, nH), cv2.INTER_CUBIC with:
cv2.warpAffine(newImg, M, (nW, nH), flags=cv2.INTER_CUBIC
I tried to simplify the code sample that reproduces the problem.
The code sample uses linear interpolation, 1 degree rotation, and no NaN values.
import numpy as np
import cv2
img = np.random.rand(1000, 1000)
M = cv2.getRotationMatrix2D((img.shape[1]//2, img.shape[0]//2), 1, 1) # Rotate by 1 degree
Rimg = cv2.warpAffine(img, M, (img.shape[1], img.shape[0]), flags=cv2.INTER_LINEAR) # Use Linear interpolation
Rimg = Rimg[20:-20, 20:-20] # Crop the part without the margins.
print(np.percentile(img, [20, 50, 80])) #[0.20005696 0.49990526 0.79954818]
print(np.percentile(Rimg, [20, 50, 80])) #[0.32244747 0.4998595 0.67698961]
cv2.imshow('img', img)
cv2.imshow('Rimg', Rimg)
cv2.waitKey()
cv2.destroyAllWindows()
When we disable the interpolation,
Rimg = cv2.warpAffine(img, M, (img.shape[1], img.shape[0]), flags=cv2.INTER_NEAREST)
The percentiles are: [0.19943713 0.50004768 0.7995525 ].
Simpler example for showing that averaging elements changes the distribution:
A = np.random.rand(10000000)
B = (A[0:-1:2] + A[1::2])/2 # Averaging every two elements.
print(np.percentile(A, [20, 50, 80])) # [0.19995436 0.49999472 0.80007232]
print(np.percentile(B, [20, 50, 80])) # [0.31617922 0.50000145 0.68377251]
Why does interpolation skews the distribution towered the median?
I am not a mathematician.
I am sure you can get a better explanation...
Here is an intuitive example:
Assume there is list of values with uniform distribution in range [0, 1].
Assume there is a zero value in the list:
[0.2, 0.7, 0, 0.5... ]
After averaging every two sequential elements, the probability for getting a zero element in the output list is very small (only two sequential zeros result a zero).
The example shows that averaging pushes the extreme values towered the center.

Get 3D point on directional light ray in Blender Python given Euler angles

I am trying to get a 3Dpoint on Sun light in Blender 3D, so that I can use it to specify directional light target position in Three JS. I have read from this How to convert Euler angles to directional vector? I could not get it. Please let me know how to get it.
I think it is a good question. In blender, since the unit vector starts from the z-axis (the light points down when initialized), I think you could use the last column of the total rotation matrix. The function for calculating the total rotation matrix is given here. Here is a modification of the function that will return a point at unit distance in the direction of the light source:
def getCosinesFromEuler(roll,pitch,yaw):
Rz_yaw = np.array([
[np.cos(yaw), -np.sin(yaw), 0],
[np.sin(yaw), np.cos(yaw), 0],
[ 0, 0, 1]])
Ry_pitch = np.array([
[ np.cos(pitch), 0, np.sin(pitch)],
[ 0, 1, 0],
[-np.sin(pitch), 0, np.cos(pitch)]])
Rx_roll = np.array([
[1, 0, 0],
[0, np.cos(roll), -np.sin(roll)],
[0, np.sin(roll), np.cos(roll)]])
rotMat = Rz_yaw # Ry_pitch # Rx_roll
return rotMat # np.array([0,0,1])
And it can be called like this :
# assuming ob is the light object
roll = ob.rotation_euler.x
pitch = ob.rotation_euler.y
yaw = ob.rotation_euler.z
x,y,z = getCosinesFromEuler(roll,pitch,yaw)
And this point (x,y,z) needs to be subtracted from the position of the light object to get a point at unit distance on the ray.

interpolate.interp1d linear plot doesn't agree with new inputs to the function

I have used scipy.interpolate.interp1d to have a linear interpolation between two arrays with float values. Then, I plotted the interpolation function with matplotlib. However, I noticed that some new values (that weren't originally included in the arrays representing x and y data) yield different results when plugged into the interpolation function, than what the plot suggests.
I am essentially trying to find the intersection points between a few lines that are parallel to the x-axis and the interpolation function's linear curve. By research online, I saw that many people use scipy's interpolate.interp1d for this purpose.
Here is the code:
from scipy import interpolate
import matplotlib.pyplot as plt
# Data
size = [12, 9, 6.5, 4.8, 2, 0.85, 0.45, 0.15, 0.07]
poW = [100, 99, 98, 97, 94, 80, 50, 6, 1]
# Approximate function f: size = f(poW)
f = interpolate.interp1d(poW, size, kind="linear")
# Here I create the plot
plt.axes(xscale='log') # scale x-axis
plt.plot(size, poW, "bs", # add data points with blue squares
f(poW), poW, "b") # add a blue trendline
# Draw D_10 as an additional point
plt.plot(f(10), 10, "rx", markersize=15)
# Draw D_30 as an additional point
plt.plot(f(30), 30, "rx", markersize=15)
# Draw D_60 as an additional point
plt.plot(f(60), 60, "rx", markersize=15)
plt.show()
The additional points I plot in the last 3 lines before plt.show(), don't correspond to the same positions indicated by the plot of the interpolation function itself. This is pretty interesting for me, and I can't seem to locate the problem here. I am pretty new to matplotlib and scipy, so I am sure I must be missing something. Any help or pointing in the right direction will be appreciated!

matplotlib: controlling position of y axis label with multiple twinx subplots

I wrote a Python script based on matplotlib that generates curves based on a common timeline. The number of curves sharing the same x axis in my plot can vary from 1 to 6 depending on user options.
Each of the data plotted use different y scales and require a different axis for drawing. As a result, I may need to draw up to 5 different Y axes on the right of my plot. I found the way in some other post to offset the position of the axes as I add new ones, but I still have two issues:
How to control the position of the multiple axes so that the tick labels don't overlap?
How to control the position of each axis label so that it is placed vertically at the bottom of each axis? And how to preserve this alignment as the display window is resized, zoomed-in etc...
I probably need to write some code that will first query the position of the axis and then a directive that will place the label relative to that position but I really have no idea how to do that.
I cannot share my entire code because it is too big, but I derived it from the code in this example. I modified that example by adding one extra plot and one extra axis to more closely match what intend to do in my script.
import matplotlib.pyplot as plt
def make_patch_spines_invisible(ax):
ax.set_frame_on(True)
ax.patch.set_visible(False)
for sp in ax.spines.values():
sp.set_visible(False)
fig, host = plt.subplots()
fig.subplots_adjust(right=0.75)
par1 = host.twinx()
par2 = host.twinx()
par3 = host.twinx()
# Offset the right spine of par2. The ticks and label have already been
# placed on the right by twinx above.
par2.spines["right"].set_position(("axes", 1.2))
# Having been created by twinx, par2 has its frame off, so the line of its
# detached spine is invisible. First, activate the frame but make the patch
# and spines invisible.
make_patch_spines_invisible(par2)
# Second, show the right spine.
par2.spines["right"].set_visible(True)
par3.spines["right"].set_position(("axes", 1.4))
make_patch_spines_invisible(par3)
par3.spines["right"].set_visible(True)
p1, = host.plot([0, 1, 2], [0, 1, 2], "b-", label="Density")
p2, = par1.plot([0, 1, 2], [0, 3, 2], "r-", label="Temperature")
p3, = par2.plot([0, 1, 2], [50, 30, 15], "g-", label="Velocity")
p4, = par3.plot([0,0.5,1,1.44,2],[100, 102, 104, 108, 110], "m-", label="Acceleration")
host.set_xlim(0, 2)
host.set_ylim(0, 2)
par1.set_ylim(0, 4)
par2.set_ylim(1, 65)
host.set_xlabel("Distance")
host.set_ylabel("Density")
par1.set_ylabel("Temperature")
par2.set_ylabel("Velocity")
par3.set_ylabel("Acceleration")
host.yaxis.label.set_color(p1.get_color())
par1.yaxis.label.set_color(p2.get_color())
par2.yaxis.label.set_color(p3.get_color())
par3.yaxis.label.set_color(p4.get_color())
tkw = dict(size=4, width=1.5)
host.tick_params(axis='y', colors=p1.get_color(), **tkw)
par1.tick_params(axis='y', colors=p2.get_color(), **tkw)
par2.tick_params(axis='y', colors=p3.get_color(), **tkw)
par3.tick_params(axis='y', colors=p4.get_color(), **tkw)
host.tick_params(axis='x', **tkw)
lines = [p1, p2, p3, p4]
host.legend(lines, [l.get_label() for l in lines])
# fourth y axis is not shown unless I add this line
plt.tight_layout()
plt.show()
When I run this, I obtain the following plot:
output from above script
In this image, question 2 above means that I would want the y-axis labels 'Temperature', 'Velocity', 'Acceleration' to be drawn directly below each of the corresponding axis.
Thanks in advance for any help.
Regards,
L.
What worked for me was ImportanceOfBeingErnest's suggestion of using text (with a line like
host.text(1.2, 0, "Velocity" , ha="left", va="top", rotation=90,
transform=host.transAxes))
instead of trying to control the label position.

Plotting a smoothed area on a map from a set of points in R

how do I plot an area around a set of points on a map in R? e.g.
map('world')
map.axes()
p <- matrix(c(50, 50, 80, 100, 70, 40, 25, 60), ncol=2) # make some points
points(p, pch=19, col="red")
polygon(p, col="blue")
... which gives me a polygon with a vertex at each of the points, but it looks rather crappy. Is there any way to "smooth" the polygon into some sort of curve?
One option is to make a polygon bounded by a Bézier curve, using the bezier function in the Hmisc package. However I cannot get the start/end point to join up neatly. For example:
## make some points
p <- matrix(c(50, 50, 80, 100, 70, 40, 25, 60), ncol=2)
## add the starting point to the end
p2 <- cbind(1:5,p[c(1:4,1),])
## linear interpolation between these points
t.coarse <- seq(1,5,0.05)
x.coarse <- approx(p2[,1],p2[,2],xout=t.coarse)$y
y.coarse <- approx(p2[,1],p2[,3],xout=t.coarse)$y
## create a Bezier curve
library(Hmisc)
bz <- bezier(x.coarse,y.coarse)
library(maps)
map('world')
map.axes()
polygon(bz$x,bz$y, col=rgb(0,0,1,0.5),border=NA)
Here's one way, draw the polygon and make it as pretty as you like. This really has nothing to do with areas on maps, more about how you generate the vertices of your polygon.
library(maps)
p <- matrix(c(50, 50, 80, 100, 70, 40, 25, 60), ncol=2)
plot(p, pch = 16, col = "red", cex = 3, xlim = range(p[,1]) + c(-10,10), ylim = range(p[,2]) + c(-5, 5))
map(add = TRUE)
#click until happy, right-click "stop" to finish
p <- locator(type = "l")
map()
polygon(cbind(p$x, p$y), col = "blue")
Otherwise you could interpolate intermediate vertices and smooth them somehow, and in the context of a lon/lat map maybe with use reprojection to get more realistic line segments - but depends on your purpose.

Resources