The main library of COMPAS
Overview
The main library consists of a core package and several additional packages for integration of the core into CAD software. The core package defines all real functionality. The CAD packages simply provide a unified framework for processing, visualising and interacting with datastructures and geometrical objects, and for building user interfaces in different CAD software.
Core functionality
To deal with the different academic backgrounds, programming skills, computational experience, and best/accepted practices of its users and their respective fields, COMPAS is implemented primarily in Python and designed to be entirely independent of the functionality of CAD software. As a result, it can be used on different platforms and in combination with external software and libraries, and at the same time take advantage of the various scientific and non-scientific libraries available in the Python ecosystem itself. Furthermore, and perhaps more importantly, it ensures that research based on COMPAS is not tied to a specific CAD-based ecosystem.
Currently compas contains several sub-packages, which can be divided into four categories.
Helpers
compas.com
: communication with external softwarecompas.files
: handlers for file formats related to geometry definition, cad interoperability, manufacturingcompas.interop
: interoperability with C/C++ code and librariescompas.utilities
: other useful things
Datastructures
compas.datastructures
: mesh (half-edge), network (graph), volmesh (half-plane)
Algorithms
compas.geometry
: geometry processingcompas.numerical
: numerical methods, solvers, …compas.topology
: combinatorics, traversal, subdivision, …
Visualisation
compas.plotters
: 2D visualisation, dynamic plots, basic interactioncompas.viewers
: basic 3D visualisation
CAD integration
The core functionality of compas is implemented independent of the functionality provided by CAD software. This ensures that research based on COMPAS is not tied to a specific tool chain en can be used more flexibly in different environments and on different platforms.
However, in the context of this framework CAD tools are obviously indispensible tools to construct and manipulate geometry, apply constraints interactively, make user interfaces, or even just to use as viewer for running scripts. The CAD helper packages (compas_blender, compas_maya, compas_rhino) provide a unified and consistent interface to CAD tools and their ecosystems.
Tutorial
Working with datastructures
Network, Mesh, VolMesh
The main library of the COMPAS framework contains three fundamental data structures:
Network
Mesh
VolMesh
These can be used as-is, but they can also be easily extended or combined to form entirely different data structures. For this tutorial, we will use the mesh data structure to demonstrate the general principles and give an overview of the possibilities.

Construction
All datastructures come with factory constructors. These are implemented as class
methods (using the @classmethod
decoreator) and are named using the following
pattern .from_xxx
.
mesh = Mesh.from_data(...)
mesh = Mesh.from_json(...)
mesh = Mesh.from_obj(...)
mesh = Mesh.from_vertices_and_faces(...)
mesh = Mesh.from_polygons(...)
mesh = Mesh.from_polyhedron(...)
mesh = Mesh.from_points(...)
compas also provides sample data that can be used together with the constructors, for example for debugging or to generate example code.
from __future__ import print_function
import compas
from compas.datastructures import Mesh
mesh = Mesh.from_obj(compas.get('faces.obj'))
print(mesh)
# ================================================================================
# Mesh summary
# ================================================================================
#
# - name: Mesh
# - vertices: 36
# - edges: 60
# - faces: 25
# - vertex degree: 2/4
# - face degree: 2/4
#
# ================================================================================
Printing the mesh produces a summary of the mesh’s properties: the number of vertices, edges and faces and information about vertex and face degree.
Data
All data accessors are iterators; they are meant to be iterated over. Lists of data have to be constructed explicitly.
mesh.vertices()
mesh.faces()
mesh.halfedges()
mesh.edges()
from __future__ import print_function
import compas
from compas.datastructures import Mesh
mesh = Mesh.from_obj(compas.get('faces.obj'))
for key in mesh.vertices():
print(key)
for key, attr in mesh.vertices(True):
print(key, attr)
print(list(mesh.vertices()))
print(mesh.number_of_vertices())
from __future__ import print_function
import compas
from compas.datastructures import Mesh
mesh = Mesh.from_obj(compas.get('faces.obj'))
for fkey in mesh.faces():
print(fkey)
for fkey, attr in mesh.faces(True):
print(fkey, attr)
print(len(list(mesh.faces()))
print(mesh.number_of_faces())
Topology
mesh.is_valid()
mesh.is_regular()
mesh.is_connected()
mesh.is_manifold()
mesh.is_orientable()
mesh.is_trimesh()
mesh.is_quadmesh()
mesh.vertex_neighbours()
mesh.vertex_degree()
mesh.vertex_faces()
mesh.vertex_neighbourhood()
mesh.face_vertices()
mesh.face_halfedges()
mesh.face_neighbours()
mesh.face_neighbourhood()
mesh.face_vertex_ancestor()
mesh.face_vertex_descendant()
import compas
from compas.datastructures import Mesh
from compas.plotters import MeshPlotter
mesh = Mesh.from_obj(compas.get('faces.obj'))
plotter = MeshPlotter(mesh)
root = 17
nbrs = mesh.vertex_neighbours(root, ordered=True)
text = {nbr: str(i) for i, nbr in enumerate(nbrs)}
text[root] = root
facecolor = {nbr: '#cccccc' for nbr in nbrs}
facecolor[root] = '#ff0000'
plotter.draw_vertices(
text=text,
facecolor=facecolor,
radius=0.15
)
plotter.draw_faces()
plotter.draw_edges()
plotter.show()

Geometry
mesh.vertex_coordinates()
mesh.vertex_area()
mesh.vertex_centroid()
mesh.vertex_normal()
mesh.face_coordinates()
mesh.face_area()
mesh.face_centroid()
mesh.face_center()
mesh.face_normal()
mesh.face_flatness()
mesh.edge_coordinates()
mesh.edge_vector()
mesh.edge_direction()
mesh.edge_length()
mesh.edge_midpoint()
import compas
from compas.datastructures import Mesh
from compas.plotters import MeshPlotter
mesh = Mesh.from_obj(compas.get('faces.obj'))
plotter = MeshPlotter(mesh)
plotter.draw_vertices()
plotter.draw_faces(text={fkey: '%.1f' % mesh.face_area(fkey) for fkey in mesh.faces()})
plotter.draw_edges()
plotter.show()

Geometry processing
Applying algorithms
Using C/C++ code
Summary
In this tutorial we will write a smoothing function in C++ and make it available directly in Python. We will also use a callback to live visualise the iterations of the algorithm and to dynamically change the boundary conditions. An implementation of the code in this tutorial is available in the geometry package:
compas.geometry.smooth_centroid_cpp()
Requirements
a C++ compiler (for example g++, which is part of the GNU compiler collection)
Setup
For this tutorial, we will use the following files and folders:
+ smoothing_cpp
+ src
- main.cpp
- smoothing.so
- smoothing.py
The smoothing function
First, the C++ code. The smoothing function will implement a simple barycentric smoothing algorithm, in which at every iteration, each vertex is moved to the barycentre of its neighbours.
By the way, I have no real experience in writing C++ code, so i am sure that this can be done a lot more elegantly and efficiently. I would be happy to hear about any and all suggestions (vanmelet@ethz.ch).
#include <vector>
using namespace std;
extern "C"
{
typedef void callback(int k);
void smooth_centroid(int v, int *nbrs, int *fixed, double **vertices, int **neighbours, int kmax, callback func);
}
void smooth_centroid(int v, int *nbrs, int *fixed, double **vertices, int **neighbours, int kmax, callback func)
{
int k;
int i;
int j, n;
double cx, cy, cz;
vector< vector<double> > xyz(v, vector<double>(3, 0.0));
for (k = 0; k < kmax; k++) {
// make a copy of the current vertex positions
for (i = 0; i < v; i++) {
xyz[i][0] = vertices[i][0];
xyz[i][1] = vertices[i][1];
xyz[i][2] = vertices[i][2];
}
// move each vertex to the barycentre of its neighbours
for (i = 0; i < v; i++) {
// skip the vertex if it is fixed
if (fixed[i]) {
continue;
}
cx = 0.0;
cy = 0.0;
cz = 0.0;
for (j = 0; j < nbrs[i]; j++) {
n = neighbours[i][j];
cx += xyz[n][0];
cy += xyz[n][1];
cz += xyz[n][2];
}
vertices[i][0] = cx / nbrs[i];
vertices[i][1] = cy / nbrs[i];
vertices[i][2] = cz / nbrs[i];
}
// call the callback
func(k);
}
}
The ctypes
wrapper
Looking a the signature of the C++ function, the code is expecting the following input arguments:
int v
int *nbrs
int *fixed
double **vertices
int **neighbours
int kmax
callback func
Or, in other words:
the number of vertices, as an integer
the number of neighbours per vertex, as a an array of integers
a mask identifying the fixed vertices, as an array of integers (0/1)
the vertex coordinates, as a two-dimensional array of doubles
the vertex neighbours, as a two-dimensional array of integers
the maximum number of iterations, as an integer
the callback function, as a function of type callback
Note that the sizes of the arrays are unknown at compile time, since they depend on the number of vertices in the system. Therefore they are passed as pointers. My understanding of this is based on whatever google spat out and a few SO posts…
https://stackoverflow.com/questions/8767166/passing-a-2d-array-to-a-c-function
https://stackoverflow.com/questions/8767166/passing-a-2d-array-to-a-c-function/17569578#17569578
We want to be able to call the function from Python, which essentially boils down to something like this:
import ctypes
import compas
from compas.datastructures import Mesh
from compas.plotters import MeshPlotter
from compas.interop.core.cpp.xdarray import Array1D
from compas.interop.core.cpp.xdarray import Array2D
# get the C++ smoothing library
smoothing = ctypes.cdll.LoadLibrary('smoothing.so')
# make a mesh
mesh = Mesh.from_obj(compas.get('faces.obj'))
# extract the required data for smoothing
vertices = mesh.get_vertices_attributes('xyz')
adjacency = [mesh.vertex_neighbours(key) for key in mesh.vertices()]
fixed = [int(mesh.vertex_degree(key) == 2) for key in mesh.vertices()]
v = len(vertices)
nbrs = [len(adjacency[i]) for i in range(v)]
neighbours = [adjacency[i] + [0] * (10 - nbrs[i]) for i in range(v)]
kmax = 50
# ==============================================================================
# convert the python data to C-compatible types
# ==============================================================================
# ...
# ==============================================================================
# make a plotter for visualisation
plotter = MeshPlotter(mesh, figsize=(10, 7))
# plot the original line geometry as a reference
lines = []
for a, b in mesh.edges():
lines.append({
'start': mesh.vertex_coordinates(a, 'xy'),
'end' : mesh.vertex_coordinates(b, 'xy'),
'color': '#cccccc',
'width': 0.5
})
plotter.draw_lines(lines)
# plot the starting point
plotter.draw_vertices()
plotter.draw_edges()
plotter.update(pause=0.5)
# ==============================================================================
# define the callback function
# ==============================================================================
def callback(k):
print(k)
# update the plot
# and change the boundary conditions
# ...
# ==============================================================================
# ==============================================================================
# set the argument types for the smoothing function
# and call it with C-compatible data
# ==============================================================================
smoothing.smooth_centroid.argtypes = [...]
smoothing.smooth_centroid(...)
# ==============================================================================
C-compatible types and data
Some of these conversion are quite trivial. For example, converting an integer is simply:
c_v = ctypes.c_int(v)
Also the 1D arrays are not too complicated. For example:
c_fixed_type = ctypes.c_int * v
c_fixed_data = c_fixed_type(*fixed)
The 2D arrays are already a bit trickier. For example:
c_vertex_type = ctypes.c_double * 3
c_vertices_type = ctypes.POINTER(ctypes.c_double) * v
c_vertices_data = c_vertices_type(*[c_vertex_type(x, y, z) for x, y, z in vertices])
Converting the callback is also quite straightforward:
c_callback_type = ctypes.CFUNCTYPE(None, c_int)
c_callback = c_callback_type(callback)
To simplify the construction of C-compatible types, and C-compatible data,
there are a few helper classes in compas.interop
:
compas.interop.core.cpp.xdarray.Array1D
compas.interop.core.cpp.xdarray.Array2D
compas.interop.core.cpp.xdarray.Array3D
With these helpers, the code for the conversion becomes:
# ==============================================================================
# convert the python data to C-compatible types
# ==============================================================================
c_nbrs = Array1D(nbrs, 'int')
c_fixed = Array1D(fixed, 'int')
c_vertices = Array2D(vertices, 'double')
c_neighbours = Array2D(neighbours, 'int')
c_callback = ctypes.CFUNCTYPE(None, ctypes.c_int)
# ==============================================================================
Then we let the smoothing function what it can expect in terms of types by setting the argument types of the callable:
# ==============================================================================
# set the argument types for the smoothing function
# and call it with C-compatible data
# ==============================================================================
smoothing.smooth_centroid.argtypes = [
c_int,
c_nbrs.ctype,
c_fixed.ctype,
c_vertices.ctype,
c_neighbours.ctype,
c_int,
c_callback
]
smoothing.smooth_centroid(
c_int(v),
c_nbrs.cdata,
c_fixed.cdata,
c_vertices.cdata,
c_neighbours.cdata,
c_int(kmax),
c_callback(wrapper)
)
# ==============================================================================
The last step is to define the functionality of the callback. The goal is to visualise the changing geometry and to change the location of the fixed points during the smoothing process; in C++, but from Python.
# ==============================================================================
# define the callback function
# ==============================================================================
def callback(k):
print(k)
xyz = c_vertices.cdata
# change the boundary conditions
if k < kmax - 1:
xyz[18][0] = 0.1 * (k + 1)
# update the plot
plotter.update_vertices()
plotter.update_edges()
plotter.update(pause=0.001)
for key, attr in mesh.vertices(True):
attr['x'] = xyz[key][0]
attr['y'] = xyz[key][1]
attr['z'] = xyz[key][2]
# ==============================================================================
The result
Putting it all together, we get the following script. Simply copy-paste it and run…
import ctypes
from ctypes import *
import compas
from compas.datastructures import Mesh
from compas.plotters import MeshPlotter
from compas.interop.core.cpp.xdarray import Array1D
from compas.interop.core.cpp.xdarray import Array2D
# get the C++ smoothing library
smoothing = ctypes.cdll.LoadLibrary('smoothing.so')
# make a mesh
mesh = Mesh.from_obj(compas.get('faces.obj'))
# extract the required data for smoothing
vertices = mesh.get_vertices_attributes('xyz')
adjacency = [mesh.vertex_neighbours(key) for key in mesh.vertices()]
fixed = [int(mesh.vertex_degree(key) == 2) for key in mesh.vertices()]
v = len(vertices)
nbrs = [len(adjacency[i]) for i in range(v)]
neighbours = [adjacency[i] + [0] * (10 - nbrs[i]) for i in range(v)]
kmax = 50
# convert the python data to C-compatible types
c_nbrs = Array1D(nbrs, 'int')
c_fixed = Array1D(fixed, 'int')
c_vertices = Array2D(vertices, 'double')
c_neighbours = Array2D(neighbours, 'int')
c_callback = CFUNCTYPE(None, c_int)
# make a plotter for visualisation
plotter = MeshPlotter(mesh, figsize=(10, 7))
# plot the original line geometry as a reference
lines = []
for a, b in mesh.edges():
lines.append({
'start': mesh.vertex_coordinates(a, 'xy'),
'end' : mesh.vertex_coordinates(b, 'xy'),
'color': '#cccccc',
'width': 0.5
})
plotter.draw_lines(lines)
# plot the starting point
plotter.draw_vertices(facecolor={key: '#000000' for key in mesh.vertices() if mesh.vertex_degree(key) == 2})
plotter.draw_edges()
plotter.update(pause=0.5)
# define the callback function
def callback(k):
print(k)
xyz = c_vertices.cdata
# change the boundary conditions
if k < kmax - 1:
xyz[18][0] = 0.1 * (k + 1)
# update the plot
plotter.update_vertices()
plotter.update_edges()
plotter.update(pause=0.001)
for key, attr in mesh.vertices(True):
attr['x'] = xyz[key][0]
attr['y'] = xyz[key][1]
attr['z'] = xyz[key][2]
# set the argument types for the smoothing function
# and call it with C-compatible data
smoothing.smooth_centroid.argtypes = [
c_int,
c_nbrs.ctype,
c_fixed.ctype,
c_vertices.ctype,
c_neighbours.ctype,
c_int,
c_callback
]
smoothing.smooth_centroid(
c_int(v),
c_nbrs.cdata,
c_fixed.cdata,
c_vertices.cdata,
c_neighbours.cdata,
c_int(kmax),
c_callback(callback)
)
# keep the plotting window alive
plotter.show()
CAD environments
This setup can also be used in CAD environments.
Assuming that “if it works in RhinoPython, it works everywhere”, here is a script for Rhino
that does the same as the one above,
but uses compas.geometry.smooth_centroid_cpp()
to make things a bit simpler.
from __future__ import print_function
from __future__ import absolute_import
from __future__ import division
import compas
import compas_rhino
from compas.datastructures import Mesh
from compas.geometry import smooth_centroid_cpp
from compas_rhino.helpers import MeshArtist
kmax = 50
# make a mesh
# and set the default vertex and edge attributes
mesh = Mesh.from_obj(compas.get('faces.obj'))
edges = list(mesh.edges())
# extract numerical data from the datastructure
vertices = mesh.get_vertices_attributes(('x', 'y', 'z'))
adjacency = [mesh.vertex_neighbours(key) for key in mesh.vertices()]
fixed = [int(mesh.vertex_degree(key) == 2) for key in mesh.vertices()]
# make an artist for dynamic visualization
# and define a callback function
# for drawing the intermediate configurations
# and for changing the boundary conditions during the iterations
slider = 30 # this is the top left corner
artist = MeshArtist(mesh, layer='SmoothMesh')
artist.clear_layer()
def callback(k, xyz):
compas_rhino.wait()
print(k)
if k < kmax - 1:
xyz[slider][0] = 0.1 * (k + 1)
artist.clear_edges()
artist.draw_edges()
artist.redraw()
for key, attr in mesh.vertices(True):
attr['x'] = xyz[key][0]
attr['y'] = xyz[key][1]
attr['z'] = xyz[key][2]
xyz = smooth_centroid_cpp(vertices, adjacency, fixed, kmax=kmax, callback=callback)
for key, attr in mesh.vertices(True):
attr['x'] = xyz[key][0]
attr['y'] = xyz[key][1]
attr['z'] = xyz[key][2]
artist.clear_edges()
artist.draw_vertices()
artist.draw_edges()
artist.redraw()
Using callbacks
compas implements a callback mechanism that provides a consistent way to customise algorithms, apply constraints, visualise progress of iterative algorithms, …
Note
A callback is a function that is passed to another function as a parameter such that the latter function can call the former at any time during its own execution. Perhaps the name callback is based on the fact that through the callback the second function can “call back” into the scope where the first function was defined. Or perhaps not :), but it is a convenient way to think about it because at time of execution, the callback has access to the variables of the scope in which it was defined.
In principle, the mechanism can be summarised with the following snippets.
# algorithm.py
def algo(..., callback=None):
if callback:
if not callable(callback):
raise Exception('The callback function is not callable.')
# stuff
for k in range(kmax):
# stuffs
if callback:
callback(k)
# more stuffs
# somescript.py
from algorithm import algo
text = 'iteration number:'
def callback(k):
print(text, k)
algo(..., callback=callback)
In this case, the result would be a bit boring, because the callback would simply
print the number of the current iteration of the algorithm. Note, however, that
the callback has access to the variable text
, even though that ariable was defined
in a different context that the one in which the callback is called.
Dynamic visualisation
Throughout the main library, callbacks are often used in combination with the plotters to visualise intermediate steps of an algorithm, or to visualise the progress of an iterative algorithm. Both can be very useful mechanisms for debugging.
For example, from compas.geometry
, an code snippet visualising the progress
of an iterative smoothing algorithm (compas.geometry.mesh_smooth_centroid()
).
import compas
from compas.datastructures import Mesh
from compas.plotters import MeshPlotter
from compas.geometry import mesh_smooth_centroid
mesh = Mesh.from_obj(compas.get('faces.obj'))
fixed = [key for key in mesh.vertices() if mesh.vertex_degree(key) == 2]
plotter = MeshPlotter(mesh, figsize=(10, 7))
lines = []
for u, v in mesh.edges():
lines.append({
'start' : mesh.vertex_coordinates(u, 'xy'),
'end' : mesh.vertex_coordinates(v, 'xy'),
'color' : '#cccccc',
'width' : 0.5
})
plotter.draw_lines(lines)
plotter.draw_vertices(facecolor={key: '#ff0000' for key in fixed})
plotter.draw_faces()
plotter.draw_edges()
plotter.update(pause=1.0)
def callback(mesh, k, args):
print(k)
plotter.update_vertices()
plotter.update_faces()
plotter.update_edges()
plotter.update(pause=0.001)
mesh_smooth_centroid(mesh, kmax=50, fixed=fixed, callback=callback)
plotter.show()
We use a mesh plotter as visualisation tool.
plotter = MeshPlotter(mesh, figsize=(10, 7))
First, as a reference, we plot a set of lines corresponding to the original configuration of the mesh.
lines = []
for u, v in mesh.edges():
lines.append({
'start' : mesh.vertex_coordinates(u, 'xy'),
'end' : mesh.vertex_coordinates(v, 'xy'),
'color' : '#cccccc',
'width' : 0.5
})
plotter.draw_lines(lines)
Then we initialise the vertices, edges and faces that will be updated at every iteration to visualise the process. We also tell the plotter to pause for a second, to be able to digest the orginal configuration before the smoothing starts.
plotter.draw_vertices(facecolor={key: '#ff0000' for key in fixed})
plotter.draw_faces()
plotter.draw_edges()
plotter.update(pause=1.0)
The next step is to define the callback function that will update the plotter. The plotter has dedicated functions for this. They update the geometry of the collections of vertices, edges and faces while keeping the style attributes as they were set by the original calls to the draw functions. With a call to the general update function we update the drawing.
The callback is handed off to the smoothing algorithm, which will call it at every iteration. By default, the callback receives the mesh object and the number of the current iteration as firs and second parameter, and then any additional parameters that were passed to the algorithm.
def callback(mesh, k, args):
print(k)
plotter.update_vertices()
plotter.update_faces()
plotter.update_edges()
plotter.update(pause=0.001)
mesh_smooth_centroid(mesh, kmax=50, fixed=fixed, callback=callback)
Finally, we make sure that the plotting window remains active and visible.
plotter.show()
The result shpould be something like this.

Applying constraints
Live interaction
CAD integration
general concepts
helper = artist + selector + modifier
working in Rhino
working in Blender
working in Maya
CPython in Rhino
In Rhino, Python scripts can be used to
(from the docs what is python)
Automate a repetitive task in Rhino much faster than you could do manually.
Perform tasks in Rhino or Grasshopper that you don’t have access to in the standard set of Rhino commands or Grasshopper components.
Generate geometry using algorithms.
Many, many other things. It is a programming language after all.
Or, create
(also from the docs where can you use python in rhino)
Interactive scripts.
New custom commands.
Create new plug-ins.
Read and Write customized file formats.
Interact with cloud applications.
Create realtime links to other applications
Create customer Grasshopper components
Store and display project specific information beyond what basic Rhino can store.
Rhino runs Python scripts using IronPython 2.7. This is great because it provides access to the .NET framework. However, this also means that many (C)Python libraries are not available. For example Numpy, Scipy, Matplotlib, SimPy, Numba, NetworkX, CVXPY, Shapely, PyOpenGL, PySide, …
With compas.utilities.XFunc this limitation can be partly removed. Below is an example from the API reference.
import compas
import compas_rhino
from compas.datastructures import Mesh
from compas.utilities import XFunc
from compas_rhino.helpers import MeshArtist
mesh = Mesh.from_obj(compas.get('faces.obj'))
vertices = mesh.get_vertices_attributes('xyz')
edges = list(mesh.edges())
fixed = list(mesh.vertices_where({'vertex_degree': 2}))
q = mesh.get_edges_attribute('q', 1.0)
loads = mesh.get_vertices_attributes(('px', 'py', 'pz'), (0.0, 0.0, 0.0))
xyz, q, f, l, r = XFunc('compas.numerical.fd_numpy')(vertices, edges, fixed, q, loads)
for key, attr in mesh.vertices(True):
attr['x'] = xyz[key][0]
attr['y'] = xyz[key][1]
attr['z'] = xyz[key][2]
artist = MeshArtist(mesh)
artist.clear()
artist.draw_vertices()
artist.draw_edges()
artist.redraw()
Making tools
In this tutorial, we will make a form finding tool for Rhino providing basic user interaction, management of settings, data persistence, and different options for solving the equilibrium problem.
The goal is to link framework functionality to a Rhino toolbar through a controller
and to simplify the process of generating the required Rhino user interface file
or rui
.
Table of contents
Examples
API
Definition
Reference
compas
compas.com
compas.com
provides functionality for communicating with external software.
Matlab
Communicate with Matlab through Windows’ COM interface. |
|
Communicate with Matlab through the MATLAB engine. |
|
Communicate with Matlab through a subprocess. |
|
Communicate with Matlab through a shared session. |
Rhino
Communicate with Rhino through Window’s COM interface. |
ssh
Initialse an SSH object. |
compas.interop
This package includes utility functions for seamless integration of C and C++ code, and wrappers for external libraries.
Warning
The functionality of this package is experimental and subject to frequent change. For now, don’t use it for anything important :)
ShapeOp
|
Core
|
|
|
|
|
|
|
|
|
|
|
|
|
Citing
If you use the main library of COMPAS in a project, please refer to the GitHub repository.
@misc{compas-dev,
title = {{compas}: A framework for computational research in architecture and structures.},
author = {Tom Van Mele and Andrew Liew and Tomas Mendéz and Matthias Rippmann and others},
note = {http://compas-dev.github.io/compas/},
year = {2017},
}