Changelog¤
All notable changes to this project will be documented in this file.
The format is based on Keep a Changelog, and this project adheres to Semantic Versioning.
Unreleased¤
Added¤
Changed¤
Removed¤
[0.8.0] 2026-08-29¤
Added¤
-
Platform-logic tests for the invoke tasks (
tests/test_tasks.py): the macOS and Linux environment construction ofinvoke setupis pure logic, pinned per-OS with mocks so a refactor cannot silently break a platform nobody is sitting at. Skipped where the dev tooling is not installed. -
Rhino 8 ports of the three curved-interface examples (
scripts/rhino_cra_curve_3_blocks.py,rhino_cra_cube_curve_short.py,rhino_cra_cube_curve_tall.py) with a shared drawing module (scripts/rhino_cra_view.py) that mirrors the desktop visualization - the same mesh arrows (cylinder shaft, conical head), colors and element grouping, on toggleable Rhino layers, drawn through the compas 2 Scene API. Open in the ScriptEditor and run; the# r:header installs compas_cra on first use. -
A viewer smoke test (
tests/test_viewers.py): the fullcra_viewscene is constructed headless against the installedcompas_viewer, with only the blockingshow()stubbed, so an API drift in the viewer fails in CI instead of on a user's screen. Skipped when the viz extra is absent. -
A regression test for the penalty solver on the arch, both variants of the
06_arch_penaltyexample, pinning the penalty solution tocra_solveon the standard arch. -
invoke setupbuilds the solver and installs the package in one command, on Windows, macOS and Linux. It installs the toolchain where that is possible without root (MSYS2 packages via pacman, Homebrew formulae including thegfortransymlink thegccformula does not create; on Linux it prints theapt/dnfline, which needs root, and stops), stages IPOPT unlessbuild/ipopt/stagealready holds it, and installs editable with the right environment - on Windows that means runningbuild_ipopt.shinside the MSYS2 UCRT64 shell and pointingCMAKE_ARGSandEXTRA_LINK_DIRSat its toolchain, which was four exports to get right by hand. It is idempotent, and defaults toJOBS=1because MUMPS races under a parallel build. -
Local development instructions in the installation docs: the compilers and libraries
packaging/build_ipopt.shneeds on Linux, macOS and Windows, and the Docker/cibuildwheel route for building a wheel without installing any of them. cra_solve,cra_penalty_solveandrbe_solveappear in the API reference. They were assignments (cra_solve = cra_solve_native) rather than imports, so the documentation generator saw untyped attributes and rendered nothing for the three names that are the package's primary entry points. They are import aliases now, which changes nothing at runtime — each name is still the same function object as its_nativecounterpart.invoke docsserves the documentation atlocalhost:8000with live reload - serving is the default because mkdocs links pages by directory, which only a web server resolves, so a site opened from disk shows folder listings on every click.invoke docs --no-servebuilds intodist/docsinstead, which is what CI deploys.
Changed¤
- The documentation navigation is grouped into sections that Material renders as tabs in the header bar (
navigation.tabs), the waycompas_cgaldoes it: Getting Started, Examples, API Reference and About. The nav was a flat list before, so every page sat in the sidebar at the same level. The entries under the oldOthersection had no titles and were rendering as bare file names, and the reference entries are spelled with their full module names. No page moved or was renamed. - The CRA solvers use IPOPT's adaptive barrier update (
mu_strategy="adaptive"). CRA's complementarity constraints are degenerate and the monotone update crawls on them: the 20-block arch needed 1964 of IPOPT's 3000 permitted iterations, leaving almost no margin, and on macOS — where the wheel links Accelerate rather than OpenBLAS, and the arithmetic differs slightly — it ran out of iterations altogether and raisedsolve failed: failed (Maximum_Iterations_Exceeded). The adaptive update reaches the same answer in 668 iterations (interface resultants agree to 1e-10), and 307 rather than 2757 on a 40-block arch. The tolerances are deliberately left alone: relaxing them makes it worse, turning a solve that stops at a feasible point into a solve that exhausts the cap. test_cra_archno longer skips itself when the arch stalls, and a companion test asserts the solve keeps its iteration headroom. That skip is what let the macOS failure reach users while CI stayed green.- IPOPT is built serially (
JOBS=1). MUMPS' makefiles are missing dependencies, so a parallel build races and dies linkinglibcoinmumps— always just afterdtype3_root.F, and with coinbrew reporting nothing butBuild failed, see error output aboveand no error above it. It is intermittent, and it failed three of six pipeline runs in compas_sandbox before being pinned down. - The PyPI upload and the GitHub release moved from
pipeline.ymlintorelease.yml. Trusted publishing matches thejob_workflow_refclaim, which for a job defined inside a reusable workflow names the reusable file, so uploading frompipeline.ymlpresentspipeline.ymlto a publisher configured forrelease.ymland fails withinvalid-publisher. This is measured, not theoretical: compas_sandbox hit exactly that on the first release that reached the upload after the same refactor. - What the wheels actually bundle. IPOPT 3.14.19 is compiled from source by
packaging/build_ipopt.sh(via coinbrew) as static libraries, andlibipoptandlibcoinmumpsare linked into thecompas_cra._native._coreextension. There is noipoptexecutable, no.nlfiles and no subprocess: a solve is a function call. MUMPS is the linear solver, which is what CRA relies on; HSL is deliberately absent because it is not redistributable. BLAS/LAPACK is the one piece that differs by platform — a static OpenBLAS on Linux and Windows, Apple's Accelerate on macOS — and that difference is exactly why the arch stalled on Mac and not elsewhere. The remaining runtimes (the Fortran runtime, OpenBLAS where it is dynamic) stay shared and are grafted into the wheel by the platform repair tools: auditwheel on Linux, delocate on macOS, delvewheel on Windows. Licences travel with the binaries: IPOPT is EPL-2.0, MUMPS and the ASL are permissive, OpenBLAS is BSD-3-Clause, and the statically linked libgfortran/libgcc are covered by the GCC Runtime Library Exception. - One package again: the IPOPT binding is built into
compas_craitself ascompas_cra._native, andcompas_craships as platform wheels for CPython 3.9-3.13 on Windows, macOS (Apple Silicon and Intel) and manylinux (x86_64 and aarch64).pip install compas_crainstalls exactly one distribution, solver included. - The build backend is scikit-build-core, which drives the CMake project at the repository root. It reads no
requirements.txt, so the dependencies now live inpyproject.toml. - The cibuildwheel settings live in
[tool.cibuildwheel]inpyproject.tomlrather than in workflow environment variables, socibuildwheelreproduces the CI wheel locally with no environment set. Only the runner-dependent parts (workspace paths, the macOS deployment target, the MSYS2 location) stay inpipeline.yml. - One CI pipeline for every push and every release:
build.yml(pushes and PRs to main) andrelease.yml(v*tags) both call the reusablepipeline.yml, which differs only by itspublishinput. A release therefore runs the exact chain that was already green on main — IPOPT from source, all five platforms, the smoke tests, the test suite against a built wheel and the docs — and then publishes it.wheels.ymlanddocs.ymlare gone, folded into that pipeline. packaging/check_release.pynow checks for thecompas_cra._native._coreextension rather than a vendoredipoptexecutable, which the statically linked build no longer ships, and additionally requires every supported CPython on every platform. Verified against the artifacts of the PR build: it passes the complete set and rejects a partial one.invoke releaseis defined intasks.pyinstead of coming fromcompas_invocations2, without its localpython -m buildstep: building a wheel here needs a staged IPOPT tree, and the published artifacts are built by CI on all five platforms regardless.- The documentation is built with mkdocs (mkdocs-material + mkdocstrings) instead of sphinx, following
compas_model. Every page is markdown: the API reference is five one-linecompas_cra.<module>pages instead of six hand-maintained.rstfiles plus 80 checked-inautosummarystubs, and the changelog and licence pages include the repository's own files rather than duplicating them. The docs dependencies are adocsextra inpyproject.toml;invoke docsand the CI docs job both runmkdocs build --strict, so a broken link or a missing page now fails the build. - Two docstrings that documented parameters the functions do not take:
CRA_Assembly.add_to_interfacesdescribed atypeargument it never had, andArchdocumentedninstead ofnum_blocksand omittedextra_support. packaging/build_ipopt.shno longer trusts the third-party source downloads. Theget.ASLandget.Mumpsscripts fetch their tarballs with a barecurl -L -O, with no integrity check and no retry, so a stalled transfer lands a short file that is then gunzipped anyway — which is how an aarch64 build failed withgzip: MUMPS_5.8.2.tar.gz: not in gzip formatafter receiving 54 kB of a 4.3 MB tarball. The script now pointsCURL_HOME/WGETRCat a config that abandons and retries a stalled transfer, and checks thatThirdParty/ASL/solversandThirdParty/Mumps/MUMPSactually exist, re-running theget.*script that came up empty (a secondcoinbrew fetchwill not: it only runsget.*when the clone's revision changed).invoke releaseno longer deletes the staged IPOPT tree. It calledcompas_invocations2.build.clean, whose default removesbuild/- which in this repository is wherepackaging/build_ipopt.shstages IPOPT, and whatCMakeLists.txtdefaultsIPOPT_PREFIXto. Every release therefore threw away about fifteen minutes of build and left the nextpip install -e .failing withNo IPOPT build at IPOPT_PREFIX=.... It is called withbuilds=Falsenow, sodist/and the egg-info still go and the stage tree stays.pip install -e ".[dev]"installs the documentation stack too, because[dev]now includes[docs]. Neither extra could runinvoke docson its own -[dev]has no mkdocs and[docs]has no invoke - so the command the installation instructions gave produced an environment the documented task did not run in.pymdown-extensionsis declared in thedocsextra.mkdocs.ymlconfigurespymdownx.*directly, so it is a direct dependency; it arrived only as a transitive dependency ofmkdocs-material.- CI builds the documentation with
invoke docsrather than its own copy of themkdocs buildcommand line, so the local task and the pipeline cannot drift apart. - The development instructions start from a
uvenvironment and state thatpip install -e ".[dev]"is the only install step, list theinvoketasks and which of them need the compiled solver (onlytestandrelease- the documentation is generated fromsrc/, not from an imported package), and note thatconda install ipoptcannot stand in forbuild_ipopt.shbecause conda-forge builds IPOPT shared against a separatemumps-seqwhileCMakeLists.txtlinks it statically. - The documentation is deployed on every push to
main, not only from a release tag. The deploy step was gated oninputs.publish, which onlyrelease.ymlsets, so merging a documentation fix built the site and threw it away and the published site tracked the last tag rather thanmain. It costs no extra CI:build.ymlalready runs the whole pipeline on every push tomain, so the wheel the docs are built against exists either way. - Every URL points at
BlockResearchGroup/compas_cra.site_url,repo_url, the[project.urls]block, the README badges,CITATION.cffand the links in the tutorial and contribution pages all named thepetrasvestartasfork, so the published site advertised a canonical URL that is not where it is served from - GitHub Pages serves it atblockresearchgroup.github.io/compas_cra. requirements.txtinstalls the documentation and linting toolchain in one command, without building the package. An extra cannot do this: installingcompas_cra[docs]buildscompas_cra, which compiles the solver. The documentation never needs it.- Two links in the README that were broken independently of the rename: the banner image pointed into
docs/_images, which has not existed since the mkdocs migration moved it todocs/assets/images, and the examples link pointed at alatest/examples.htmlpath on github.com rather than at the documentation site. - An editable install is self-contained on Windows, the way a repaired wheel is. The extension links MSYS2's shared runtimes (libgfortran, libopenblas, libstdc++), and Python does not search PATH for extension DLLs, so importing
compas_cra._nativedied withDLL load failedanywhere delvewheel had not vendored them - which is every editable install. The CMake install now copies the runtime DLL closure next to the module whenBUNDLE_RUNTIME_DLLS=ON, whichinvoke setuppasses; the package code does not know MSYS2 exists, and the CI wheels keep delvewheel's repair (the option defaults to OFF, so they never carry a second copy). pytestis part of thedevextra.invoke testwas unusable from the documented install - CI happened to install pytest separately.- After
invoke setup, a plainuv pip install -e .rebuilds the extension with no special environment, and nothing is configured globally.CMakeLists.txtfinds the MinGW toolchain itself on Windows (and refuses MSVC with an explanation - the GCC-built static archives cannot be linked by it, and CMake's Visual Studio default produced a LNK1181 ten minutes in), the venv's activation scripts carry the toolchain PATH and the Ninja generator (written once byinvoke setup, venv-scoped), and the runtime DLL bundling defaults to on for Windows builds - the CI wheels pass-DBUNDLE_RUNTIME_DLLS=OFFand keep delvewheel's repair. Python edits need no reinstall at all: the editable install servessrc/directly. - The viewers work with compas_viewer 2.x again.
cra_viewpassed plain Python lists toviewer.scene.add, which raisedSceneObjectNotRegisteredError: <class 'list'>on the first example anyone ran with a viewer; every list is wrapped inCollectionnow, and two stalesize=/color=kwargs becamepointsize=/pointcolor=. - Force and weight arrows are meshes again - cylinder shaft, conical head, widths scaling with length - restoring the compas_view2
Arrowshape and itshead_portion=0.2, head_width=0.07, body_width=0.02parameters, verified against the documentation screenshots. The port had replaced them with compas_viewer'sVectorObject, which draws a fixed pixel-width line with a four-sided pyramid head that degenerates to a sliver for axis-parallel directions - the weight arrows, drawn at the old world-unit width as a pixel width, rendered as disembodied heads. Arrows are added at opacity 0.999 on purpose: the transparency pass draws after the semi-transparent block faces, so an arrow inside a block stays bold as it did in compas_view2. - The uneven interface resultants on the curved examples are the solver's true optimum, not an artifact: the fully converged solution (
tol=1e-8, status optimal, 356 iterations) matches the fast acceptable-level solution to 1.7e-6 across all 72 sub-interface resultants, and their sum equals the supported weight. The visual difference against the old screenshots was the absolute-width arrow heads exaggerating small forces. - The CRA solver's acceptable-level tolerances relaxed from 1e-8 to 1e-6. The wedge and curved-blocks examples converge to ~1e-8 violation and then cannot reach the hard tolerances - at 1e-8 acceptance they died a hair above the line (
Restoration_Failedat 4.6e-8,Maximum_Iterations_Exceededhovering at 1.6e-8). The hard tolerances are unchanged; relaxing acceptance only adds a stopping opportunity. - The penalty solver uses the adaptive barrier update too - same degenerate complementarity constraints as the CRA solver, same crawl under the monotone update.
- The
06_arch_penaltyexample passesd_bnd=1e-2: with the default 1e-3 the solve exhausts even a 9000-iteration cap under both barrier strategies, at 1e-2 it converges in ~65 iterations, and on the standard arch the penalty resultants then agree withcra_solveto 1e-3 - same physics, feasible bound. All 18 example scripts now run to completion, verified headless. - Resultant force arrows are red only for interfaces in net tension (
sum_n < 0) - the rule the published screenshots were made with (commit15e5edc, 2022-08-17). The per-vertex<= -1e-5check added later turned whole interfaces red over complementarity-relaxation noise (vertex normals reach -2e-3 on shelf interfaces that are in overall compression), which is why the shelf example showed red arrows where its screenshot shows green. Genuine tension still shows: net-tension interfaces render red, and per-vertex tension renders as red nodal arrows, unchanged. - Block and support edges draw at the same width (1.5), block edges in dark gray, support edges in the support salmon - matching the reference screenshots instead of the 4-wide support outlines.
09_bridgerunscra_solveagain - the example had been switched tocra_penalty_solve, producing a visibly different solution from its screenshot. Verified against the 2022 code in an era-exact environment: identical resultants to five decimals, no tension anywhere. The view flags also now match the screenshot (forcesdirect=True): the image was made with flags that were never committed, and the image is the contract.- The solver restores the published force distributions. The CRA system is square, and until IPOPT 3.14.11 square problems were special-cased: the convergence check ignored dual feasibility and bound complementarity, so IPOPT stopped at the first primal-feasible point of the barrier path - an interior point where every contact face carries force. Every figure in the paper (Kao et al. 2022, doi:10.1016/j.cad.2022.103216) and the docs is such a point. IPOPT 3.14.12 removed the special case, and the same problems then converge to a degenerate vertex - on the curved-interface examples the whole load lands on 8 of 72 sub-faces and the rest go to zero, which is what this package has shipped since the bundled IPOPT became newer than that. Root-caused by building IPOPT 3.14.9, 3.14.11 and 3.14.14 from source against the same MUMPS 5.9: 3.14.11 still spreads (identically to 3.14.9), 3.14.14 concentrates - the flip is exactly at 3.14.12, the release whose changelog documents the square-problem change; not MUMPS, and not this repository - every code generation from the screenshot-day commit to today produces both solutions depending only on the binary. The fix sets
mu_target=1e-5(with tolerances to match and a raised iteration cap): the barrier stops at the interior point deliberately instead of by accident of an old binary. Calibrated against the published figures themselves rather than a rebuilt era binary - the old square-problem shortcut stopped wherever its check happened to trip, so a from-source 3.14.11 stops at a lower barrier level (force staircase of 4.5x) than the author's 2022 conda/macOS build, whose figures show near-uniform arrows. 1e-5 reproduces the figures: cube-curve-tall max/median 1.11, cube-curve-short 1.20, all 72 faces loaded. Equilibrium stays exact at 1e-8, and the arch reaches the same resultants (1.9571/0.8437) in 270 iterations. Pinning the old IPOPT was evaluated and rejected: correctly built it links and runs fine, but its stopping level is platform luck - the very thing that made the published results irreproducible in the first place. 13_curve-3-blocksruns its original published parameters again (density=0.1, scale=5). They only solve in the barrier-interior regime; under strict optimization they exhaust the iteration cap on every IPOPT generation, which is why the author had switched to density=1 as a workaround days after the screenshot.invoke setupcarriesMACOSX_DEPLOYMENT_TARGET=11.0through the IPOPT build and the editable install on macOS - the same value CI pins, for Apple Silicon and Intel alike - so the static libraries and the extension agree on a target instead of failing to link against the Python build's older default. It also checks for the Xcode Command Line Tools up front (build_ipopt.sh needs xcrun for the Accelerate stub) rather than failing fifteen minutes into the build.- The venv activation patch re-prepends the venv's own Scripts directory after the MSYS2 toolchain path: ucrt64in carries a python.exe of its own, and it was shadowing the venv's - a bare
pythonin an activated shell ran the wrong interpreter.
Removed¤
- Removed the separate
compas_cra_nativedistribution and itsnative/pyproject.toml; the binding source stays innative/, built by the rootCMakeLists.txt. An install from source (pip install ., editable included) now compiles the extension and needspackaging/build_ipopt.shto have run first. - Removed
requirements.txt,requirements-dev.txtandrequirements-viz.txt;pip install -e ".[dev]"replacespip install -r requirements-dev.txt. - Removed the
build_ghuser_componentstask and itsghuserconfiguration fromtasks.py; the paths pointed atsrc/compas_notebook, and compas_cra ships no Grasshopper components. - Removed
docs/conf.py, every.rstpage, the generateddocs/api/tree and thesphinx_compas2_themedependency.
[0.7.2] 2026-08-23¤
Added¤
Changed¤
- One ordered release pipeline in
release.yml: native wheels build first (IPOPT compiled from source), the pure package is tested against the just-built native wheel, then publish native → publish cra → GitHub release → docs.native.ymlis build-only push CI;docs.ymlbuilds on main pushes only; the lint job runs without installing the package.
Removed¤
[0.7.1] 2026-08-23¤
Added¤
Changed¤
compas_cra_native0.1.1: the audit-hardened binding (sparsity index range checks, transient-callback-exception recovery, automatic quasi-Newton fallback, wall-time status) actually ships to PyPI — 0.1.0 predated those fixes andskip-existinghad kept re-uploads out.- Rhino scripts pin
compas_cra>=0.7.0so cached ScriptEditor environments upgrade off the removed executable path.
Removed¤
[0.7.0] 2026-08-23¤
Added¤
- Added
cra_penalty_problemandrbe_problemNLP formulations with exact analytic derivatives, and the matching native solverscra_penalty_solve_nativeandrbe_solve_native, validated against the pyomo implementations before those were removed (max force difference 1.9e-14 for RBE, 7.1e-9 for the penalty formulation).
Changed¤
cra_solve,cra_penalty_solveandrbe_solveare now the in-process native solvers.compas_crais a pure Python package again — one universal wheel — with the compiled solver coming from thecompas_cra_nativedependency.- The native wheel workflow builds the Linux wheels with cibuildwheel inside the manylinux containers, in the style of compas_cgal.
Removed¤
- Removed the bundled IPOPT executable, the pyomo formulations and the pyomo dependency. There is no solver executable anywhere anymore: solving happens in-process through the nanobind extension, which also removes the Windows antivirus false-positive problem structurally.
[0.6.6] 2026-08-23¤
Added¤
Changed¤
compas_cra_nativeis now a dependency ofcompas_cra(on Python < 3.14), sopip install compas_cra— or a single# r: compas_craline in Rhino — brings the in-process solver along automatically.
Removed¤
[0.6.5] 2026-08-23¤
Added¤
Changed¤
- Hardened the native binding after a three-stage independent audit: sparsity index range checks (out-of-range values from Python now raise instead of crashing), a solve that converges despite a transient callback exception keeps its solution,
hessian_approximation=limited-memoryis set automatically when no Hessian callback is given, andMaximum_WallTime_Exceededis reported by name. - The native backend no longer accepts iteration-capped points; only near-converged endings (
Restoration_Failed,Search_Direction_Becomes_Too_Small) qualify for the feasible-point acceptance check, matching the executable path's failure behavior. - The Rhino example scripts solve with
cra_solve_native(in-process, no executable involved). - macOS arm64 native wheels are built on macOS 14, so they install on macOS 14+.
Removed¤
[0.6.4] 2026-08-23¤
Added¤
- Added
compas_cra.nlp, a solver-agnostic sparse NLP layer, andcompas_cra.equilibrium.cra_problem, the CRA optimisation problem formulated directly in numpy/scipy with exact analytic gradient, Jacobian and Lagrangian Hessian (no pyomo involved). - Added
compas_cra_native(innative/): IPOPT + MUMPS compiled into a Python extension module with nanobind, so CRA problems solve in-process — no bundled executable, no subprocess, no.nlfiles. Results match the pyomo + executable path on the test suite (bit-identical on the cube fixtures, < 1e-5 relative force difference on the arch). - Added
cra_solve_native, a drop-in alternative tocra_solveusing the binding.
Changed¤
Removed¤
[0.6.3] 2026-08-23¤
Added¤
- Added the
COMPAS_CRA_IPOPTenvironment variable to override the solver location, for machines where antivirus or application-control policies block the bundled binary. - The Windows
ipopt.exenow carries a version resource (product, publisher, version, license), and the release workflow supports Authenticode signing via Azure Trusted Signing when the signing secrets are configured.
Changed¤
Removed¤
[0.6.2] 2026-08-23¤
Added¤
Changed¤
- Lowered
requires-pythonto>= 3.9so the package installs into Rhino 8's bundled CPython 3.9.
Removed¤
[0.6.1] 2026-08-23¤
Added¤
Changed¤
Removed¤
[0.6.0] 2026-08-26¤
Added¤
- Added a bundled, statically linked IPOPT executable to the platform wheels, so
pip install compas_crano longer needs conda, homebrew or a manually downloaded solver. Wheels are built for Windows, macOS (Apple Silicon and Intel) and manylinux (x86_64 and aarch64) by.github/workflows/release.yml. - Added
packaging/with the scripts that build IPOPT 3.14.19 from source with coinbrew (MUMPS linear solver, no HSL), pack the platform wheels and test them in a clean environment. - Added
compas_cra._ipoptto locate the solver, and acompas-cra-ipoptconsole script to check which solver will be used. - Added the
vizoptional dependencies (pip install compas_cra[viz]). - Added
packaging/check_release.py, run by the publish job before uploading: a release is rejected unless it carries a wheel for every supported platform and each wheel actually contains an ipopt executable.
Changed¤
- Declared the runtime dependencies (
compas,compas_assembly,numpy,pyomo,scipy,shapely) inrequirements.txt, which was empty. cra_solve,cra_penalty_solveandrbe_solvenow build their solver withcompas_cra.equilibrium._solver.ipopt_solver, which points pyomo at the bundled executable. Solver options and tolerances are unchanged.-
Rewrote the installation instructions around pip; the manual Windows workaround for missing ipopt binaries is no longer needed.
-
Replaced kernel-layer
MatrixConstraintwith standardpyo.Constraintrules instatic_equilibrium_constraintsfor compatibility with recent Pyomo versions. - Pinned Python to
< 3.14for viewer compatibility.
Removed¤
[0.5.0] 2024-10-21¤
Added¤
Changed¤
- Changed compas_view2 to compas_viewer.
- Changed sample files to COMPAS 2 format.
- Fixed bug in temp viewer arrow solution.
Removed¤
- Removed
matplotlibfrom env files. - Removed
piprequirements. - Removed incompatible interface info.
[0.4.0] 2024-03-02¤
Added¤
- Add delete block and blocks methods in CRA_Assembly class.
- A script to export mesh to json in Rhino.
Changed¤
Removed¤
[0.3.0] 2022-11-06¤
Added¤
Changed¤
Removed¤
[0.2.2] 2022-09-29¤
Added¤
- Add example folder directory to tutorial docs for easy access.
Changed¤
- Fix some typos and wrong url links.
- Change ipopt installation guide using conda.