brinraeven
brinraeven

Reputation: 33

How to return points on a square as an array?

I am currently trying to figure out how to return the perimeter of a square that can then be used as an input to calculate a charge density. Specifically, the charge is uniform around the perimeter of the square and is then used to calculate the potential and charge density.

This is the code that I have for a point charge.

def Q(i,j,x_max,y_max,delta):
     x_dist=math.exp(-(i*delta-x_max/2.0)*(i*delta-x_max/2.0)/(1.0*delta*delta))
     y_dist=math.exp(-(j*delta-y_max/2.0)*(j*delta-y_max/2.0)/(1.0*delta*delta))
     return x_dist*y_dist

I've found this very intriguing website that hints that I can accomplish this by using the equation x^(a very large number) + y^(a very large number) = 1 to approximate a square. This intrigued me, so I was trying to create the points on a square to use as the source of the charge.

http://polymathprogrammer.com/2010/03/01/answered-can-you-describe-a-square-with-1-equation/

I've tried the below, but that, of course, only returns one point.

return math.pow(x_dist,1000000)-1

Any suggestions? Thanks!

Upvotes: 2

Views: 1213

Answers (2)

a_guest
a_guest

Reputation: 36299

You can compute the points on the perimeter directly using np.linspace. Counting x from left to right and y from bottom to top, you can use the following:

import numpy as np


def square(top_left, l, n):
    top = np.stack(
        [np.linspace(top_left[0], top_left[0] + l, n//4 + 1),
         np.full(n//4 + 1, top_left[1])],
         axis=1
    )[:-1]
    left = np.stack(
        [np.full(n//4 + 1, top_left[0]),
         np.linspace(top_left[1], top_left[1] - l, n//4 + 1)],
         axis=1
    )[:-1]
    right = left.copy()
    right[:, 0] += l
    bottom = top.copy()
    bottom[:, 1] -= l
    return np.concatenate([top, right, bottom, left])

Which gives for example:

import matplotlib.pyplot as plt

s = square((0, 0), 2, 400)
plt.plot(s[:, 0], s[:, 1], 'o')
plt.grid()
plt.show()

Square


If you cannot use numpy for whatever reasons, it's not too much trouble to (re-)create the functionality to the required degree (see for example the source code of np.linspace as an orientation):

def linspace(a, b, n):
    return [a + (b - a) / (n - 1) * i for i in range(n)]


def full(n, x):
    return n * [x]


def square(top_left, l, n):
    top = list(zip(
        linspace(top_left[0], top_left[0] + l, n//4 + 1),
        full(n//4 + 1, top_left[1])
    ))
    left = list(zip(
        full(n//4 + 1, top_left[0]),
        linspace(top_left[1], top_left[1] - l, n//4 + 1)
    ))
    right = [(x + l, y) for x, y in left]
    bottom = [(x, y - l) for x, y in top]
    return top + right + bottom + left

Upvotes: 3

NaN
NaN

Reputation: 2322

rectangles and squares can be readily made using numpy. The pattern can be used as a seed and repeated if you need a grid of rectangles. For example, produce a 5 unit square

import numpy as np
dx = 5
dy = 5
X = [0.0, 0.0, dx, dx, 0.0]       # X, Y values for a unit square
Y = [0.0, dy, dy, 0.0, 0.0]
a = np.array(list(zip(X, Y)))

A bit of overkill for small polygons, but einsum can readily be brought into play for calculating perimeters of geometries or hundreds or thousands of coordinate pairs.

a = np.reshape(a, (1,) + a.shape)
diff = a[:, 0:-1] - a[:, 1:]
d_leng = np.sqrt(np.einsum('ijk,ijk->ij', diff, diff)).squeeze()
length = np.sum(d_leng.flatten())

so for the simple polygon (first and last point are duplicates to ensure closure), the coordinates and side and total lengths are as follows

d_leng
array([5., 5., 5., 5.])

length
20.0

a
array([[[0., 0.],
        [0., 5.],
        [5., 5.],
        [5., 0.],
        [0., 0.]]])

If you need a different origin point prior to beginning, that can be accomplished simply...

a + [10, 10]
array([[[10., 10.],
        [10., 15.],
        [15., 15.],
        [15., 10.],
        [10., 10.]]])

Upvotes: 0

Related Questions