Skip to content

Commit

Permalink
Initial work for port to N-API
Browse files Browse the repository at this point in the history
Port CGALWrap templates, macros, and one wrapped class (BBox2)
as proof of concept.
  • Loading branch information
fritzm committed Aug 5, 2019
1 parent a82319b commit 6c7943a
Show file tree
Hide file tree
Showing 22 changed files with 236 additions and 401 deletions.
52 changes: 30 additions & 22 deletions binding.gyp
Original file line number Diff line number Diff line change
Expand Up @@ -5,37 +5,47 @@

'sources': [
'src/cgal.cc',
'src/AffTransformation2.cc',
'src/Arrangement2.cc',
'src/Arrangement2Face.cc',
'src/Arrangement2Halfedge.cc',
'src/Arrangement2Vertex.cc',
'src/BBox2.cc',
'src/Curve2.cc',
'src/D2.cc',
'src/Direction2.cc',
'src/Line2.cc',
'src/NefPolyhedron2.cc',
'src/Point2.cc',
'src/Polygon2.cc',
'src/PolygonSet2.cc',
'src/PolygonWithHoles2.cc',
'src/Ray2.cc',
'src/Segment2.cc',
'src/Vector2.cc'
# 'src/AffTransformation2.cc',
# 'src/Arrangement2.cc',
# 'src/Arrangement2Face.cc',
# 'src/Arrangement2Halfedge.cc',
# 'src/Arrangement2Vertex.cc',
'src/BBox2.cc'
# 'src/Curve2.cc',
# 'src/D2.cc',
# 'src/Direction2.cc',
# 'src/Line2.cc',
# 'src/NefPolyhedron2.cc',
# 'src/Point2.cc',
# 'src/Polygon2.cc',
# 'src/PolygonSet2.cc',
# 'src/PolygonWithHoles2.cc',
# 'src/Ray2.cc',
# 'src/Segment2.cc',
# 'src/Vector2.cc'
],

'include_dirs': [ '<!@(echo $CGAL_GYP_INCLUDES)' ],
'include_dirs': [
'<!@(node -p "require(\'node-addon-api\').include")',
'<!@(echo $CGAL_GYP_INCLUDES)'
],

'dependencies': [
'<!(node -p "require(\'node-addon-api\').gyp")'
],

'conditions': [

['OS=="mac"', {
'libraries': [ 'libCGAL.a', 'libgmp.a', 'libmpfr.a', 'libboost_thread-mt.a' ],
'cflags+': ['-fvisibility=hidden'],
'xcode_settings': {
'GCC_ENABLE_CPP_EXCEPTIONS': 'YES',
'GCC_ENABLE_CPP_RTTI': 'YES',
'GCC_SYMBOLS_PRIVATE_EXTERN': 'YES', # -fvisibility=hidden
'CLANG_CXX_LIBRARY': 'libc++',
'MACOSX_DEPLOYMENT_TARGET': '10.7',
'OTHER_CPLUSPLUSFLAGS': [
'-Wno-unused-result',
'-Wno-null-pointer-arithmetic',
'<!@(echo $CGAL_GYP_CXXFLAGS)'
],
Expand All @@ -47,8 +57,6 @@
'cflags_cc!': [ '-fno-exceptions', '-fno-rtti' ],
'cflags_cc': [
'-frounding-math',
'-Wno-unused-result',
'-Wno-cast-function-type',
'<!@(echo $CGAL_GYP_CXXFLAGS)'
],
'libraries': [ '-lCGAL', '-lgmp', '-lmpfr', '-lboost_thread' ],
Expand Down
3 changes: 3 additions & 0 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,9 @@
"cpu": [
"x64"
],
"dependencies": {
"node-addon-api": "*"
},
"devDependencies": {
"jasmine": "^3.4.0",
"jasmine-console-reporter": "^3.1.0"
Expand Down
File renamed without changes.
4 changes: 2 additions & 2 deletions spec/BBox2.spec.js
Original file line number Diff line number Diff line change
Expand Up @@ -5,8 +5,8 @@ describe("CGAL.BBox2", function() {

it("should be constructable from limits", function() {
expect(function() { return new CGAL.BBox2({xmin:1, ymin:2, xmax:3, ymax:4}); }).not.toThrow();
expect(function() { return new CGAL.Line2({xmin:1, ymin:3, xmax:3}); }).toThrow();
expect(function() { return new CGAL.Line2({xmin:"foo", ymin:2, xmax:3, ymax:4}); }).toThrow();
expect(function() { return new CGAL.BBox2({xmin:1, ymin:3, xmax:3}); }).toThrow();
expect(function() { return new CGAL.BBox2({xmin:"foo", ymin:2, xmax:3, ymax:4}); }).toThrow();
});

it("should be renderable via toPOD", function() {
Expand Down
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
3 changes: 2 additions & 1 deletion spec/support/jasmine.json
Original file line number Diff line number Diff line change
@@ -1,7 +1,8 @@
{
"spec_dir": "spec",
"spec_files": [
"**/*[sS]pec.js"
"**/*.spec.js",
"!**/*.nospec.js"
],
"helpers": [
"helpers/**/*.js"
Expand Down
105 changes: 45 additions & 60 deletions src/BBox2.cc
Original file line number Diff line number Diff line change
@@ -1,96 +1,81 @@
#include "BBox2.h"
#include "cgal_args.h"
#include "napi.h"

using namespace v8;
using namespace node;
using namespace std;


const char *BBox2::Name = "BBox2";
BBox2::BBox2(Napi::CallbackInfo const& info)
: CGALWrapper(info)
{
}


char const* BBox2::Name = "BBox2";


void BBox2::RegisterMethods(Isolate *isolate)
void BBox2::AddProperties(vector<PropertyDescriptor>& properties)
{
HandleScope scope(isolate);
Local<FunctionTemplate> constructorTemplate = sConstructorTemplate.Get(isolate);
NODE_SET_PROTOTYPE_METHOD(constructorTemplate, "overlaps", Overlaps);
NODE_SET_PROTOTYPE_METHOD(constructorTemplate, "add", Add);
properties.insert(properties.end(), {
InstanceMethod("overlaps", &BBox2::Overlaps),
InstanceMethod("add", &BBox2::Add)
});
}


bool BBox2::ParseArg(Isolate *isolate, Local<Value> arg, Bbox_2 &receiver)
bool BBox2::ParseArg(Napi::Env env, Napi::Value arg, Bbox_2& receiver)
{
HandleScope scope(isolate);
Local<Context> context = isolate->GetCurrentContext();
if (arg.IsObject()) {
Napi::Object obj = arg.As<Napi::Object>();

if (sConstructorTemplate.Get(isolate)->HasInstance(arg)) {
receiver = ExtractWrapped(Local<Object>::Cast(arg));
return true;
}

if (arg->IsObject()) {
Local<Object> bounds = Local<Object>::Cast(arg);
if (obj.InstanceOf(sConstructor.Value())) {
receiver = Unwrap(obj)->mWrapped;
return true;
}

if (bounds->Get(context, SYMBOL(isolate, "xmin")).ToLocalChecked()->IsNumber() &&
bounds->Get(context, SYMBOL(isolate, "ymin")).ToLocalChecked()->IsNumber() &&
bounds->Get(context, SYMBOL(isolate, "xmax")).ToLocalChecked()->IsNumber() &&
bounds->Get(context, SYMBOL(isolate, "ymax")).ToLocalChecked()->IsNumber())
if (obj.Get("xmin").IsNumber() &&
obj.Get("ymin").IsNumber() &&
obj.Get("xmax").IsNumber() &&
obj.Get("ymax").IsNumber())
{
receiver = Bbox_2(
bounds->Get(context, SYMBOL(isolate, "xmin")).ToLocalChecked()->NumberValue(context).ToChecked(),
bounds->Get(context, SYMBOL(isolate, "ymin")).ToLocalChecked()->NumberValue(context).ToChecked(),
bounds->Get(context, SYMBOL(isolate, "xmax")).ToLocalChecked()->NumberValue(context).ToChecked(),
bounds->Get(context, SYMBOL(isolate, "ymax")).ToLocalChecked()->NumberValue(context).ToChecked()
obj.Get("xmin").As<Napi::Number>().DoubleValue(),
obj.Get("ymin").As<Napi::Number>().DoubleValue(),
obj.Get("xmax").As<Napi::Number>().DoubleValue(),
obj.Get("ymax").As<Napi::Number>().DoubleValue()
);
return true;
}

}

return false;
}


Local<Value> BBox2::ToPOD(Isolate *isolate, const Bbox_2 &box, bool precise)
Napi::Value BBox2::ToPOD(Napi::Env env, bool precise)
{
EscapableHandleScope scope(isolate);
Local<Context> context = isolate->GetCurrentContext();
Local<Object> obj = Object::New(isolate);
obj->Set(context, SYMBOL(isolate, "xmin"), Number::New(isolate, box.xmin()));
obj->Set(context, SYMBOL(isolate, "ymin"), Number::New(isolate, box.ymin()));
obj->Set(context, SYMBOL(isolate, "xmax"), Number::New(isolate, box.xmax()));
obj->Set(context, SYMBOL(isolate, "ymax"), Number::New(isolate, box.ymax()));
return scope.Escape(obj);
Napi::Object obj = Napi::Object::New(env);
obj.Set("xmin", mWrapped.xmin());
obj.Set("ymin", mWrapped.ymin());
obj.Set("xmax", mWrapped.xmax());
obj.Set("ymax", mWrapped.ymax());
return obj;
}


void BBox2::Overlaps(const v8::FunctionCallbackInfo<v8::Value> &info)
Napi::Value BBox2::Overlaps(Napi::CallbackInfo const& info)
{
Isolate *isolate = info.GetIsolate();
HandleScope scope(isolate);
try {
Bbox_2 &thisBox = ExtractWrapped(info.This());
ARGS_ASSERT(isolate, info.Length() == 1);
ARGS_PARSE_LOCAL(isolate, BBox2::ParseArg, Bbox_2, otherBox, info[0]);
return info.GetReturnValue().Set(Boolean::New(isolate, do_overlap(thisBox, otherBox)));
}
catch (const exception &e) {
isolate->ThrowException(String::NewFromUtf8(isolate, e.what(), NewStringType::kNormal).ToLocalChecked());
}
Napi::Env env = info.Env();
ARGS_ASSERT(env, info.Length() == 1);
ARGS_PARSE_LOCAL(env, BBox2::ParseArg, Bbox_2, otherBox, info[0]);
return Napi::Boolean::New(env, do_overlap(mWrapped, otherBox));
}


void BBox2::Add(const v8::FunctionCallbackInfo<v8::Value> &info)
Napi::Value BBox2::Add(Napi::CallbackInfo const& info)
{
Isolate *isolate = info.GetIsolate();
HandleScope scope(isolate);
try {
Bbox_2 &thisBox = ExtractWrapped(info.This());
ARGS_ASSERT(isolate, info.Length() == 1);
ARGS_PARSE_LOCAL(isolate, BBox2::ParseArg, Bbox_2, otherBox, info[0]);
return info.GetReturnValue().Set(BBox2::New(isolate, thisBox + otherBox));
}
catch (const exception &e) {
isolate->ThrowException(String::NewFromUtf8(isolate, e.what(), NewStringType::kNormal).ToLocalChecked());
}
Napi::Env env = info.Env();
ARGS_ASSERT(env, info.Length() == 1);
ARGS_PARSE_LOCAL(env, BBox2::ParseArg, Bbox_2, otherBox, info[0]);
return BBox2::New(env, mWrapped + otherBox);
}
25 changes: 11 additions & 14 deletions src/BBox2.h
Original file line number Diff line number Diff line change
Expand Up @@ -3,38 +3,35 @@

#include "CGALWrapper.h"
#include "cgal_types.h"
#include "v8.h"

#include <vector>

class BBox2 : public CGALWrapper<BBox2, Bbox_2>
{
public:

// The name to be used for our JS class.
static const char *Name;
BBox2(Napi::CallbackInfo const& info);

// Add our function templates to the package exports, and return string to be used to name
// the class and constructor in JS. Called indirectly at module load time via the module
// init function.
static void RegisterMethods(v8::Isolate *isolate);
static char const* Name;
static void AddProperties(std::vector<PropertyDescriptor>& properties);

// Attempt to parse a v8 argument into the CGAL object referred to by receiver. Returns true
// Attempt to parse a JS argument into the CGAL object referred to by receiver. Returns true
// if parse was successful, false otherwise.
static bool ParseArg(v8::Isolate *isolate, v8::Local<v8::Value> arg, Bbox_2 &receiver);
static bool ParseArg(Napi::Env env, Napi::Value arg, Bbox_2& receiver);

// Convert a CGAL object of the wrapped class to a POD v8 object. If precise is set to false,
// Convert a CGAL object of the wrapped class to a POD JS object. If precise is set to false,
// will attempt to render in terms of doubles for coordinates, and may lose precision.
static v8::Local<v8::Value> ToPOD(v8::Isolate *isolate, const Bbox_2 &box, bool precise=true);
Napi::Value ToPOD(Napi::Env env, bool precise);

private:

//
//----- The following methods will be callable from JS. These will mostly match
//----- The following methods will be callable from JS. These will mostly match
// the semantics and names of the wrapped CGAL class.
//

static void Overlaps(const v8::FunctionCallbackInfo<v8::Value> &info);
static void Add(const v8::FunctionCallbackInfo<v8::Value> &info);
Napi::Value Overlaps(Napi::CallbackInfo const& info);
Napi::Value Add(Napi::CallbackInfo const& info);

};

Expand Down
Loading

0 comments on commit 6c7943a

Please sign in to comment.