Giter Site home page Giter Site logo

salusoft89 / planegcs Goto Github PK

View Code? Open in Web Editor NEW
14.0 6.0 2.0 1.8 MB

A webassembly wrapper for FreeCAD's 2D geometric solver.

Home Page: https://www.npmjs.com/package/@salusoft89/planegcs

License: GNU Lesser General Public License v2.1

JavaScript 0.03% Dockerfile 0.06% TypeScript 19.73% Shell 0.85% Nunjucks 3.79% CMake 0.37% C++ 72.94% C 2.23%
constraint-solver constraint-solving freecad solver solver-library typescript webassembly

planegcs's Introduction

About planegcs

Planegcs is a 2D geometric constraint solver from FreeCAD. This repository is a port of the C++ code to WebAssembly, so that it can be used in the browser or node environments. The solving is based on numeric optimization methods, such as DogLeg, Levenberg-Marquardt, BFGS or SQP. Apart from the WebAssembly module and the wrapper class, this library contains complete TypeScript annotations.

This repository includes two PDF documents created by members of the FreeCAD community in the doc folder: Sketcher Lecture (by Christoph Blaue), which is a user-level description of FreeCAD's Sketcher, and Solver manual (by Abdullah Tahiri), which is a lower-level description of the planegcs solver.

Features

  • Point, Line, Circle, Arc, Ellipse, Elliptical arc, Hyperbola, Parabola, Hyperbolical arc, Parabolical arc
  • All constraints from planegcs (see planegcs_dist/constraints.ts)
  • Reference sketch parametries or geometry properties in the constraints
  • Non-driving and temporary constraints
  • Validation code for sketch primitives (in a separate library planegcs-validation)
  • Higher-level data model (WIP)
  • B-Spline
  • Multithreading execution of QR decomposition (GcsSystem.cpp:4811,4883)
  • Support for constraints referencing other constraints

Example usage

The geometries and constraints are represented by JSON objects, which are called (sketch) primitives. A list of primitives is an input for the solver. The primitives might reference each other by their ids.

const primitives = [ 
    { id: '1', type: 'point', x: 10, y: 10, fixed: false },
    { id: '2', type: 'point', x: 20, y: 20, fixed: false },
 
    { id: '3', type: 'p2p_coincident', p1_id: '1', p2_id: '2' },
 ];

gcs_wrapper.push_primitives_and_params(primitives);
gcs_wrapper.solve();
gcs_wrapper.apply_solution();

console.log(gcs_wrapper.sketch_index.get_primitives());
// outputs
// [
//    { id: '1', type: 'point', x: 10, y: 10, fixed: false },
//    { id: '2', type: 'point', x: 10, y: 10, fixed: false },                <<< x and y changed
//    { id: '3', type: 'p2p_coincident', p1_id: '1', p2_id: '2' },
// ]

Installation and import

Install with npm install @salusoft89/planegcs.

The main class for working with planegcs is GcsWrapper and can be instantiated as follows:

import { init_planegcs_module, GcsWrapper } from '@salusoft89/planegcs';
async function init_gcs_wrapper() {
	const mod = await init_planegcs_module();
   const gcs_system_wasm = new mod.GcsSystem();
   const gcs_wrapper = new GcsWrapper(gcs_system_wasm);
   return gcs_wrapper;
}

init_gcs_wrapper().then(gcs_wrapper => {
   do_something_with_gcs_wrapper(gcs_wrapper);

   // explicit de-allocation of the Wasm memory must be called
   gcs_wrapper.destroy_gcs_module();
});

If using Vite, then you need to explicitly set the .wasm file import url:

import wasm_url from "@salusoft89/planegcs/dist/planegcs_dist/planegcs.wasm?url";
// ...
const mod = await init_planegcs_module({ locateFile: () => wasm_url });
// ...

Geometries

This library supports all geometries that are implemented in the original solver:

Point, Line, Circle

{ id: '1', type: 'point', x: 10, y: 10, fixed: false },
{ id: '2', type: 'point', x: 0, y: 0, fixed: false }

When fixed is set to true, then the point's coordinates are not changed during solving.

{ id: '3', type: 'line', p1_id: '1', p2_id: '2' }

A line is defined by two points, which must have lower ids.

{ id: '4', type: 'circle', c_id: CENTER_POINT_ID, radius: 100 }

Arc

An arc requires three points to be defined (center, start, end) and a subsequent planegcs-specific constraint arc_rules that keeps the endpoints (start_id, end_id) aligned with the start_angle and end_angle.

{ id: '5', type: 'arc', c_id: CENTER_POINT_ID, radius: 100,
 start_angle: 0, end_angle: Math.PI / 2,
 start_id: START_POINT_ID, end_id: END_POINT_ID }

{ id: '6', type: 'arc_rules', a_id: '5'  }

Ellipse

An ellipse is represented in planegcs by its minor radius (length of the semi-minor axis) and F1 (one of its focal points):

{ id: '7', type: 'ellipse', c_id: CENTER_POINT_ID, focus1_id: F1_POINT_ID, radmin: 100 }

ellipse

The ellipse can be further constrained using planegcs-internal constraints for the major and minor diameters:

{ id: '8', type: 'internal_alignment_ellipse_major_diameter', e_id: '7', p1_id: ..., p2_id: ...}
{ id: '9', type: 'internal_alignment_ellipse_minor_diameter', e_id: '7', p1_id: ..., p2_id: ...}

Elliptical arc

The elliptical arc again requires another constraint to keep the start/end points aligned:

{ id: '10', type: 'arc_of_ellipse', c_id: CENTER_POINT_ID, focus1_id: F1_POINT_ID,
  radmin: 100, start_angle: 0, end_angle: Math.PI / 2,
  start_id: START_POINT_ID, end_id: END_POINT_ID }

{ id: '11', type: 'arc_of_ellipse_rules', a_id: '10' }

Same as for the ellipse, it can be constrained by the major/minor diameter alignment constraints.

Hyperbola, Parabola, Hyperbolical arc, Parabolical arc

Defined similarly to an ellipse/elliptical arc. See the type definitions in sketch/sketch_primitive.ts.

B-Spline

B-Spline from planegcs is currently not yet fully supported. (WIP)

Constraints

Planegcs supports a wide range of constraints. All available constraint types are in planegcs_dist/constraints.ts.

The values of the constraints can be set direclty as a number, reference a sketch parameter, or reference a property of a geometry with lower ID:

  1. Parameter value as a number:
{ id: '3', type: 'p2p_distance', p1_id: '1', p2_id: '2', distance: 100 }
  1. Parameter value as a reference to a sketch parameter:
{ id: '3', type: 'p2p_angle', p1_id: '1', p2_id: '2', angle: 'my_distance' }
  1. Parameter value as a reference to a property of a geometry with ID o_id
{ 
   id: '3', 
   type: 'difference',
   param1: {
      o_id: '1',
      prop: 'x',
   },
   param2: {
      o_id: '2',
      prop: 'y',
   },
   difference: 100,
}

Currently, the object referenced with o_id can be only a geometry, referencing constraints is not supported.

Driving, Temporary flags and Scale

Each constraint has following (optional) properties:

  • driving (default true) - if set to false, then the constraint doesn't influence the geometries during solving, but instead can be used for measurements

  • temporary (default false) - if set to true, then the constraint is only enforced so much that it doesn't conflict with other constraints. This is useful for constraints for mouse dragging in a Sketcher user interface. Temporary constraints don't reduce DOF. The presence of temporary constraints changes the algorithm used for solving in planegcs, regardless of the configured algorithm.

  • scale (default 1) - sets the scale for an error of a constraint. Scale lower than 1 makes the constraint less prioritized by the solver and vice versa.

Solving

Following methods can be called in the GcsWrapper to change the behavior of solving:

  • set_max_iterations(max_iterations: number) - sets the maximum number of iterations for the solver. Default is 100.
  • set_convergence_threshold(convergence_threshold: number) - sets the convergence threshold for the solver. Default is 1e-10.
  • set_debug_mode(debug_mode: DebugMode) - sets the level of Debug, where DebugMode is NoDebug, Minimal, or IterationLevel

Furthermore, the solving can be altered via setting the algorithm to the solve method:

Note: when the sketch containts constraints with a flag temporary set to true, then the parameter is ignored and instead the SQP algorithm is used.

Developing

Install Docker and Node.js.

Build command: npm run build:all, which consists of these steps:

  • npm run build:docker - pulls/builds the docker image for building C++ files from FreeCAD
  • npm run build:bindings - creates a C++ binding for the FreeCAD API (partly by scanning the source code)
  • npm run build:wasm - builds the planegcs.wasm and planegcs.js files from the C++ binding and source files

To run a script that updates the FreeCAD source files, run npm run update-freecad. It is not guaranteed that the parsing scripts will work with newer versions of FreeCAD, so you may have to adjust them.

Tests

The tests for the library are in the test folder and can be run with npm test. A subset of tests that doesn't require the compiled WebAssembly module can be run with npm run test:basic.

planegcs's People

Contributors

thes01 avatar

Stargazers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

Watchers

 avatar  avatar  avatar  avatar  avatar  avatar

planegcs's Issues

Error when bundling with webpack

Hi, great wrapper around PlaneGCS, something I was looking for a long time, thank you for putting this project together!

I am trying to use this npm module in my js lib I am packing with webpack as UMD module.
When I try to build with this this package installed and imported I do get an error about module resolution.

In particular it complains that:

ERROR in ./node_modules/@salusoft89/planegcs/dist/planegcs_dist/planegcs.js 9:174-203
Module not found: Error: Can't resolve './' in '/Users/rafal/Projects/LTBL/planegcs-js/node_modules/@salusoft89/planegcs/dist/planegcs_dist'
resolve './' in '/Users/rafal/Projects/LTBL/planegcs-js/node_modules/@salusoft89/planegcs/dist/planegcs_dist'
  Parsed request is a directory
  using description file: /Users/rafal/Projects/LTBL/planegcs-js/node_modules/@salusoft89/planegcs/package.json (relative path: ./dist/planegcs_dist)
    using description file: /Users/rafal/Projects/LTBL/planegcs-js/node_modules/@salusoft89/planegcs/package.json (relative path: ./dist/planegcs_dist)
      as directory
        existing directory /Users/rafal/Projects/LTBL/planegcs-js/node_modules/@salusoft89/planegcs/dist/planegcs_dist
          using description file: /Users/rafal/Projects/LTBL/planegcs-js/node_modules/@salusoft89/planegcs/package.json (relative path: ./dist/planegcs_dist)
            using path: /Users/rafal/Projects/LTBL/planegcs-js/node_modules/@salusoft89/planegcs/dist/planegcs_dist/index
              using description file: /Users/rafal/Projects/LTBL/planegcs-js/node_modules/@salusoft89/planegcs/package.json (relative path: ./dist/planegcs_dist/index)
                no extension
                  /Users/rafal/Projects/LTBL/planegcs-js/node_modules/@salusoft89/planegcs/dist/planegcs_dist/index doesn't exist
                .tsx
                  /Users/rafal/Projects/LTBL/planegcs-js/node_modules/@salusoft89/planegcs/dist/planegcs_dist/index.tsx doesn't exist
                .ts
                  /Users/rafal/Projects/LTBL/planegcs-js/node_modules/@salusoft89/planegcs/dist/planegcs_dist/index.ts doesn't exist
                .js
                  /Users/rafal/Projects/LTBL/planegcs-js/node_modules/@salusoft89/planegcs/dist/planegcs_dist/index.js doesn't exist
 @ ./node_modules/@salusoft89/planegcs/dist/index.js 14:0-63 15:0-32 20:29-49
 @ ./src/index.ts 37:0-72 43:45-65 47:38-48

ERROR in /Users/rafal/Projects/LTBL/planegcs-js/src/index.ts
1:49-71
[tsl] ERROR in /Users/rafal/Projects/LTBL/planegcs-js/src/index.ts(1,50)
      TS2792: Cannot find module '@salusoft89/planegcs'. Did you mean to set the 'moduleResolution' option to 'nodenext', or to add aliases to the 'paths' option?
ts-loader-default_e3b0c44298fc1c14

Does it have to do with how target javascript version emscripten is confoigured for ES5/ES6 and new js modules vs commonJS ?
Any pointers on why this happens and potentially how to solve would be greatly appreciated!

the test project attached as zip
planegcs-js.zip

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    ๐Ÿ–– Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. ๐Ÿ“Š๐Ÿ“ˆ๐ŸŽ‰

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google โค๏ธ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.