Skip to content

Commit b247a53

Browse files
authored
Merge pull request #916 from compas-dev/random-samples
Random samples of stuff
2 parents fee3643 + 698e6c6 commit b247a53

File tree

11 files changed

+526
-18
lines changed

11 files changed

+526
-18
lines changed

CHANGELOG.md

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -26,6 +26,10 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
2626
* Added version-based installation for Blender.
2727
* Added several shape artists to `compas_ghpython`: `BoxArtist`, `CapsuleArtist`, `ConeArtist`, `CylinderArtist`, `PolygonArtist`, `PolyhedronArtist`, `SphereArtist`, `TorusArtist` and `VectorArtist`.
2828
* Added support for CLR generic dictionaries to the `compas.data` decoders.
29+
* Added `Graph.node_sample`, `Graph.edge_sample`.
30+
* Added `Halfedge.vertex_sample`, `Halfedge.edge_sample`, `Halfedge.face_sample`.
31+
* Added `Halfface.vertex_sample`, `Halfface.edge_sample`, `Halfface.face_sample`, `Halfface.cell_sample`.
32+
* Added `Mesh.from_meshgrid`.
2933

3034
### Changed
3135

src/compas/artists/meshartist.py

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -65,13 +65,13 @@ class MeshArtist(Artist):
6565
default_color = (0.0, 0.0, 0.0)
6666
default_vertexcolor = (1.0, 1.0, 1.0)
6767
default_edgecolor = (0.0, 0.0, 0.0)
68-
default_facecolor = (1.0, 1.0, 1.0)
68+
default_facecolor = (0.9, 0.9, 0.9)
6969

7070
default_vertexsize = 5
7171
default_edgewidth = 1.0
7272

7373
def __init__(self, mesh, **kwargs):
74-
super(MeshArtist, self).__init__(**kwargs)
74+
super(MeshArtist, self).__init__()
7575

7676
self._mesh = None
7777
self._vertices = None

src/compas/datastructures/graph/graph.py

Lines changed: 31 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -314,6 +314,37 @@ def get_any_edges(self, n):
314314
"""
315315
return sample(list(self.edges()), n)
316316

317+
def node_sample(self, size=1):
318+
"""Get a list of identifiers of a random set of n nodes.
319+
320+
Parameters
321+
----------
322+
size : int, optional
323+
The size of the sample.
324+
325+
Returns
326+
-------
327+
list
328+
The identifiers of the nodes.
329+
330+
"""
331+
return sample(list(self.nodes()), size)
332+
333+
def edge_sample(self, size=1):
334+
"""Get the identifiers of a set of random edges.
335+
336+
Parameters
337+
----------
338+
size : int, optional
339+
The size of the sample.
340+
341+
Returns
342+
-------
343+
list
344+
The identifiers of the random edges.
345+
"""
346+
return sample(list(self.edges()), size)
347+
317348
def key_index(self):
318349
"""Returns a dictionary that maps node dictionary keys to the
319350
corresponding index in a node list or array.

src/compas/datastructures/halfedge/halfedge.py

Lines changed: 64 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -260,6 +260,51 @@ def get_any_face_vertex(self, fkey):
260260
"""
261261
return self.face_vertices(fkey)[0]
262262

263+
def vertex_sample(self, size=1):
264+
"""A random sample of the vertices.
265+
266+
Parameters
267+
----------
268+
size : int, optional
269+
The number of vertices in the random sample.
270+
271+
Returns
272+
-------
273+
list
274+
The identifiers of the vertices.
275+
"""
276+
return sample(list(self.vertices()), size)
277+
278+
def edge_sample(self, size=1):
279+
"""A random sample of the edges.
280+
281+
Parameters
282+
----------
283+
size : int, optional
284+
The number of edges in the random sample.
285+
286+
Returns
287+
-------
288+
list
289+
The identifiers of the edges.
290+
"""
291+
return sample(list(self.edges()), size)
292+
293+
def face_sample(self, size=1):
294+
"""A random sample of the faces.
295+
296+
Parameters
297+
----------
298+
size : int, optional
299+
The number of faces in the random sample.
300+
301+
Returns
302+
-------
303+
list
304+
The identifiers of the faces.
305+
"""
306+
return sample(list(self.faces()), size)
307+
263308
def key_index(self):
264309
"""Returns a dictionary that maps vertex dictionary keys to the
265310
corresponding index in a vertex list or array.
@@ -2471,10 +2516,27 @@ def is_face_on_boundary(self, key):
24712516

24722517
def halfedge_after(self, u, v):
24732518
face = self.halfedge_face(u, v)
2474-
w = self.face_vertex_after(face, v)
2519+
if face is not None:
2520+
w = self.face_vertex_after(face, v)
2521+
return v, w
2522+
nbrs = self.vertex_neighbors(u, ordered=True)
2523+
w = nbrs[0]
24752524
return v, w
24762525

24772526
def halfedge_before(self, u, v):
24782527
face = self.halfedge_face(u, v)
2479-
t = self.face_vertex_before(face, u)
2528+
if face is not None:
2529+
t = self.face_vertex_before(face, u)
2530+
return t, u
2531+
nbrs = self.vertex_neighbors(u, ordered=True)
2532+
t = nbrs[-1]
24802533
return t, u
2534+
2535+
def vertex_edges(self, vertex):
2536+
edges = []
2537+
for nbr in self.vertex_neighbors(vertex):
2538+
if self.has_edge((vertex, nbr)):
2539+
edges.append((vertex, nbr))
2540+
else:
2541+
edges.append((nbr, vertex))
2542+
return edges

src/compas/datastructures/halfface/halfface.py

Lines changed: 61 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,7 @@
22
from __future__ import division
33
from __future__ import print_function
44

5-
from random import choice
5+
from random import choice, sample
66

77
from compas.datastructures.datastructure import Datastructure
88
from compas.datastructures.attributes import VertexAttributeView
@@ -268,6 +268,66 @@ def get_any_face_vertex(self, face):
268268
"""
269269
return choice(self.halfface_vertices(face))
270270

271+
def vertex_sample(self, size=1):
272+
"""Get the identifiers of a set of random vertices.
273+
274+
Parameters
275+
----------
276+
size : int, optional
277+
The size of the sample.
278+
279+
Returns
280+
-------
281+
list of int
282+
The identifiers of the vertices.
283+
"""
284+
return sample(list(self.vertices()), size)
285+
286+
def edge_sample(self, size=1):
287+
"""Get the identifiers of a set of random edges.
288+
289+
Parameters
290+
----------
291+
size : int, optional
292+
The size of the sample.
293+
294+
Returns
295+
-------
296+
list of int
297+
The identifiers of the edges.
298+
"""
299+
return sample(list(self.edges()), size)
300+
301+
def face_sample(self, size=1):
302+
"""Get the identifiers of a set of random faces.
303+
304+
Parameters
305+
----------
306+
size : int, optional
307+
The size of the sample.
308+
309+
Returns
310+
-------
311+
list of int
312+
The identifiers of the faces.
313+
"""
314+
return sample(list(self.faces()), size)
315+
316+
def cell_sample(self, size=1):
317+
"""Get the identifiers of a set of random cells.
318+
319+
Parameters
320+
----------
321+
size : int, optional
322+
The size of the sample.
323+
324+
Returns
325+
-------
326+
list of int
327+
The identifiers of the cells.
328+
"""
329+
return sample(list(self.cells()), size)
330+
271331
def vertex_index(self):
272332
"""Returns a dictionary that maps vertex dictionary keys to the
273333
corresponding index in a vertex list or array.

src/compas/datastructures/mesh/mesh.py

Lines changed: 38 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,7 @@
55
import collections
66
import sys
77
from math import pi
8+
from itertools import product
89

910
import compas
1011

@@ -33,6 +34,9 @@
3334
from compas.geometry import midpoint_line
3435
from compas.geometry import vector_average
3536

37+
from compas.utilities import linspace
38+
from compas.utilities import meshgrid
39+
3640
from compas.utilities import geometric_key
3741
from compas.utilities import pairwise
3842
from compas.utilities import window
@@ -612,6 +616,40 @@ def from_polygons(cls, polygons, precision=None):
612616
def to_polygons(self):
613617
return [self.face_coordinates(fkey) for fkey in self.faces()]
614618

619+
@classmethod
620+
def from_meshgrid(cls, dx, nx, dy=None, ny=None):
621+
"""Create a mesh from faces and vertices on a regular grid.
622+
623+
Parameters
624+
----------
625+
dx : float
626+
The size of the grid in the X direction.
627+
nx : int
628+
The number of faces in the X direction.
629+
dy : float, optional
630+
The size of the grid in the Y direction, if different form X.
631+
ny : int, optional
632+
The number of faces in the Y direction, if different from Y.
633+
634+
Returns
635+
-------
636+
Mesh
637+
A mesh object.
638+
"""
639+
dy = dy or dx
640+
ny = ny or nx
641+
642+
V, U = meshgrid(linspace(0, dx, nx + 1), linspace(0, dy, ny + 1), indexing='ij')
643+
644+
quads = [[
645+
[U[i + 0][j + 0], V[i + 0][j + 0], 0],
646+
[U[i + 0][j + 1], V[i + 0][j + 1], 0],
647+
[U[i + 1][j + 1], V[i + 1][j + 1], 0],
648+
[U[i + 1][j + 0], V[i + 1][j + 0], 0]
649+
] for i, j in product(range(ny), range(nx))]
650+
651+
return cls.from_polygons(quads)
652+
615653
# --------------------------------------------------------------------------
616654
# helpers
617655
# --------------------------------------------------------------------------

src/compas_plotters/artists/circleartist.py

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -68,6 +68,7 @@ def draw(self) -> None:
6868
facecolor=self.facecolor,
6969
edgecolor=self.edgecolor,
7070
fill=self.fill,
71+
alpha=self.alpha,
7172
zorder=self.zorder
7273
)
7374
self._mpl_circle = self.plotter.axes.add_artist(circle)

src/compas_plotters/artists/ellipseartist.py

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -67,6 +67,7 @@ def draw(self) -> None:
6767
facecolor=self.facecolor,
6868
edgecolor=self.edgecolor,
6969
fill=self.fill,
70+
alpha=self.alpha,
7071
zorder=self.zorder)
7172
self._mpl_ellipse = self.plotter.axes.add_artist(ellipse)
7273

0 commit comments

Comments
 (0)