Source code for compas.geometry.interpolation.coons
from __future__ import print_function
from __future__ import absolute_import
from __future__ import division
from compas.geometry import add_vectors
from compas.geometry import scale_vector
from compas.geometry import subtract_vectors
from compas.geometry import sum_vectors
from compas.utilities import normalize_values
__all__ = [
'discrete_coons_patch',
]
[docs]def discrete_coons_patch(ab, bc, dc, ad):
"""Creates a coons patch from a set of four or three boundary
polylines (ab, bc, dc, ad).
Parameters
----------
polylines : sequence
The XYZ coordinates of the vertices of the polyline.
The vertices are assumed to be in order.
The polyline is assumed to be open:
Returns
-------
points : list of tuples
The points of the coons patch.
faces : list of lists
List of faces (face = list of vertex indices as integers)
Notes
-----
Direction and order of polylines::
b -----> c
^ ^
| |
| |
| |
a -----> d
One polyline can be None to create a triangular patch
(Warning! This will result in duplicate vertices)
For more information see [1]_ and [2]_.
References
----------
.. [1] Wikipedia. *Coons patch*.
Available at: https://en.wikipedia.org/wiki/Coons_patch.
.. [2] Robert Ferreol. *Patch de Coons*.
Available at: https://www.mathcurve.com/surfaces/patchcoons/patchcoons.shtml
Examples
--------
>>>
"""
if not ab:
ab = [ad[0]] * len(dc)
if not bc:
bc = [ab[-1]] * len(ad)
if not dc:
dc = [bc[-1]] * len(ab)
if not ad:
ad = [dc[0]] * len(bc)
n = len(ab)
m = len(bc)
n_norm = normalize_values(range(n))
m_norm = normalize_values(range(m))
array = [[0] * m for i in range(n)]
for i, ki in enumerate(n_norm):
for j, kj in enumerate(m_norm):
# first function: linear interpolation of first two opposite curves
lin_interp_ab_dc = add_vectors(scale_vector(ab[i], (1 - kj)), scale_vector(dc[i], kj))
# second function: linear interpolation of other two opposite curves
lin_interp_bc_ad = add_vectors(scale_vector(ad[j], (1 - ki)), scale_vector(bc[j], ki))
# third function: linear interpolation of four corners resulting a hypar
a = scale_vector(ab[0], (1 - ki) * (1 - kj))
b = scale_vector(bc[0], ki * (1 - kj))
c = scale_vector(dc[-1], ki * kj)
d = scale_vector(ad[-1], (1 - ki) * kj)
lin_interp_a_b_c_d = sum_vectors([a, b, c, d])
# coons patch = first + second - third functions
array[i][j] = subtract_vectors(add_vectors(lin_interp_ab_dc, lin_interp_bc_ad), lin_interp_a_b_c_d)
# create vertex list
vertices = []
for i in range(n):
vertices += array[i]
# create face vertex list
faces = []
for i in range(n - 1):
for j in range(m - 1):
faces.append([i * m + j, i * m + j + 1, (i + 1) * m + j + 1, (i + 1) * m + j])
return vertices, faces
# ==============================================================================
# Main
# ==============================================================================
if __name__ == "__main__":
import doctest
doctest.testmod(globs=globals())