<commit_before>#include "node.h"
#include "node_version.h"
#include "nan.h"
#include <string>
using namespace v8;
using namespace node;

class ContextWrap;

class ContextifyContext : public Nan::ObjectWrap {
public:
    Nan::Persistent<Context> context;
    Nan::Persistent<Object>  sandbox;
    Nan::Persistent<Object>  proxyGlobal;

    static Nan::Persistent<FunctionTemplate> jsTmpl;

    ContextifyContext(Local<Object> sbox) {
        Nan::HandleScope scope;
        sandbox.Reset(sbox);
    }

    ~ContextifyContext() {
        context.Reset();
        proxyGlobal.Reset();
        sandbox.Reset();

        // Provide a GC hint that the context has gone away. Without this call it
        // does not seem that the collector will touch the context until under extreme
        // stress.
        Nan::ContextDisposedNotification();
    }

    // We override ObjectWrap::Wrap so that we can create our context after
    // we have a reference to our "host" JavaScript object.  If we try to use
    // handle_ in the ContextifyContext constructor, it will be empty since it's
    // set in ObjectWrap::Wrap.
    void Wrap(Local<Object> handle);

    static void Init(Local<Object> target) {
        Nan::HandleScope scope;

        Local<String> className = Nan::New("ContextifyContext").ToLocalChecked();

        Local<FunctionTemplate> ljsTmpl = Nan::New<FunctionTemplate>(New);
        ljsTmpl->InstanceTemplate()->SetInternalFieldCount(1);
        ljsTmpl->SetClassName(className);
        Nan::SetPrototypeMethod(ljsTmpl, "run",       ContextifyContext::Run);
        Nan::SetPrototypeMethod(ljsTmpl, "getGlobal", ContextifyContext::GetGlobal);

        jsTmpl.Reset(ljsTmpl);
        target->Set(className, ljsTmpl->GetFunction());
    }

    static NAN_METHOD(New) {
        if (info.Length() < 1)
            return Nan::ThrowError("Wrong number of arguments passed to ContextifyContext constructor");

        if (!info[0]->IsObject())
            return Nan::ThrowTypeError("Argument to ContextifyContext constructor must be an object.");

        ContextifyContext* ctx = new ContextifyContext(info[0]->ToObject());
        ctx->Wrap(info.This());
        info.GetReturnValue().Set(info.This());
    }

    static NAN_METHOD(Run) {
        if (info.Length() == 0)
            return Nan::ThrowError("Must supply at least 1 argument to run");

        if (!info[0]->IsString())
            return Nan::ThrowTypeError("First argument to run must be a String.");

        ContextifyContext* ctx = Nan::ObjectWrap::Unwrap<ContextifyContext>(info.This());
        Local<Context> lcontext = Nan::New(ctx->context);
        Context::Scope ctxScope(lcontext);
        Local<String> code = info[0]->ToString();

        Nan::TryCatch trycatch;
        Nan::MaybeLocal<Nan::BoundScript> script;

        if (info.Length() > 1 && info[1]->IsString()) {
            ScriptOrigin origin(info[1]->ToString());
            script = Nan::CompileScript(code, origin);
        } else {
            script = Nan::CompileScript(code);
        }

        if (script.IsEmpty()) {
            trycatch.ReThrow();
            return;
        }

        Nan::MaybeLocal<Value> result = Nan::RunScript(script.ToLocalChecked());

        if (result.IsEmpty()) {
            trycatch.ReThrow();
        } else {
            info.GetReturnValue().Set(result.ToLocalChecked());
        }
    }

    static bool InstanceOf(Local<Value> value) {
        return Nan::New(jsTmpl)->HasInstance(value);
    }

    static NAN_METHOD(GetGlobal) {
        ContextifyContext* ctx = Nan::ObjectWrap::Unwrap<ContextifyContext>(info.This());
        info.GetReturnValue().Set(Nan::New(ctx->proxyGlobal));
    }
};

// This is an object that just keeps an internal pointer to this
// ContextifyContext.  It's passed to the NamedPropertyHandler.  If we
// pass the main JavaScript context object we're embedded in, then the
// NamedPropertyHandler will store a reference to it forever and keep it
// from getting gc'd.
class ContextWrap : public Nan::ObjectWrap {
public:
    static void Init(void) {
        Nan::HandleScope scope;

        Local<FunctionTemplate> tmpl = Nan::New<FunctionTemplate>();
        tmpl->InstanceTemplate()->SetInternalFieldCount(1);
        functionTemplate.Reset(tmpl);
        constructor.Reset(tmpl->GetFunction());
    }

    static Local<Context> createV8Context(Local<Object> jsContextify) {
        Nan::EscapableHandleScope scope;
        Local<Object> wrapper = Nan::NewInstance(Nan::New(constructor)).ToLocalChecked();

        ContextWrap *contextWrapper = new ContextWrap();
        contextWrapper->Wrap(wrapper);

        Nan::Persistent<Object>(jsContextify).SetWeak(contextWrapper, &ContextWrap::weakCallback, Nan::WeakCallbackType::kParameter);
        contextWrapper->ctx = Nan::ObjectWrap::Unwrap<ContextifyContext>(jsContextify);

        Local<FunctionTemplate> ftmpl = Nan::New<FunctionTemplate>();
        ftmpl->SetHiddenPrototype(true);
        ftmpl->SetClassName(Nan::New(contextWrapper->ctx->sandbox)->GetConstructorName());
        Local<ObjectTemplate> otmpl = ftmpl->InstanceTemplate();
        Nan::SetNamedPropertyHandler(otmpl,
                                     GlobalPropertyGetter,
                                     GlobalPropertySetter,
                                     GlobalPropertyQuery,
                                     GlobalPropertyDeleter,
                                     GlobalPropertyEnumerator,
                                     wrapper);
#if NODE_MODULE_VERSION <= NODE_6_0_MODULE_VERSION
        otmpl->SetAccessCheckCallbacks(GlobalPropertyNamedAccessCheck,
                                       GlobalPropertyIndexedAccessCheck);
#else
        NamedPropertyHandlerConfiguration namedPropertyHandlerConfiguration;
        IndexedPropertyHandlerConfiguration indexedPropertyHandlerConfiguration;
        otmpl->SetAccessCheckCallbackAndHandler(AccessCheckCallback,
                                                namedPropertyHandlerConfiguration,
                                                indexedPropertyHandlerConfiguration);
#endif
        return scope.Escape(Nan::New<Context>(static_cast<ExtensionConfiguration*>(NULL), otmpl));
    }

private:
    ContextWrap() :ctx(NULL) {}

    ~ContextWrap() {
    }

#if NODE_MODULE_VERSION <= NODE_6_0_MODULE_VERSION
    static bool GlobalPropertyNamedAccessCheck(Local<Object> host,
                                               Local<Value>  key,
                                               AccessType    type,
                                               Local<Value>  data) {
        return true;
    }

    static bool GlobalPropertyIndexedAccessCheck(Local<Object> host,
                                                 uint32_t      key,
                                                 AccessType    type,
                                                 Local<Value>  data) {
        return true;
    }
#else
    static bool AccessCheckCallback(Local<Context> accessing_context,
                                    Local<Object> accessed_object,
                                    Local<Value> data) {
        return true;
    }
#endif

    static void GlobalPropertyGetter(Local<String> property, const Nan::PropertyCallbackInfo<Value>& info) {
        Local<Object> data = info.Data()->ToObject();
        ContextifyContext* ctx = Nan::ObjectWrap::Unwrap<ContextWrap>(data)->ctx;

        if (!ctx)
            return;

        Nan::MaybeLocal<Value> rv = Nan::GetRealNamedProperty(Nan::New(ctx->sandbox),
                                                              property);
        if (rv.IsEmpty())
            return;

        info.GetReturnValue().Set(rv.ToLocalChecked());
    }

    static void GlobalPropertySetter(Local<String> property, Local<Value> value, const Nan::PropertyCallbackInfo<Value>& info) {
        Local<Object> data = info.Data()->ToObject();
        ContextifyContext* ctx = Nan::ObjectWrap::Unwrap<ContextWrap>(data)->ctx;

        if (!ctx)
            return;

        Nan::New(ctx->sandbox)->Set(property, value);
        info.GetReturnValue().Set(value);
    }

    static void GlobalPropertyQuery(Local<String> property, const Nan::PropertyCallbackInfo<Integer>& info) {
        Local<Object> data = info.Data()->ToObject();
        ContextifyContext* ctx = Nan::ObjectWrap::Unwrap<ContextWrap>(data)->ctx;

        if (!ctx)
            return info.GetReturnValue().Set(Nan::New<Integer>(None));

        if (!Nan::GetRealNamedProperty(Nan::New(ctx->sandbox), property).IsEmpty() ||
            !Nan::GetRealNamedProperty(Nan::New(ctx->proxyGlobal), property).IsEmpty()) {
            info.GetReturnValue().Set(Nan::New<Integer>(None));
        } else {
            info.GetReturnValue().Set(Local<Integer>());
        }
    }

    static void GlobalPropertyDeleter(Local<String> property, const Nan::PropertyCallbackInfo<Boolean>& info) {
        Local<Object> data = info.Data()->ToObject();
        ContextifyContext* ctx = Nan::ObjectWrap::Unwrap<ContextWrap>(data)->ctx;

        if (!ctx)
            return info.GetReturnValue().Set(Nan::New(false));

        bool success = Nan::New(ctx->sandbox)->Delete(property);
        info.GetReturnValue().Set(Nan::New(success));
    }

    static void GlobalPropertyEnumerator(const Nan::PropertyCallbackInfo<Array>& info) {
        Local<Object> data = info.Data()->ToObject();
        ContextifyContext* ctx = Nan::ObjectWrap::Unwrap<ContextWrap>(data)->ctx;

        if (!ctx) {
            Local<Array> blank = Array::New(0);
            return info.GetReturnValue().Set(blank);
        }

        info.GetReturnValue().Set(Nan::New(ctx->sandbox)->GetPropertyNames());
    }

    static void weakCallback(const Nan::WeakCallbackInfo<ContextWrap>& data) {
        ContextWrap *self = data.GetParameter();
        self->ctx = NULL;
    }

    static Nan::Persistent<FunctionTemplate> functionTemplate;
    static Nan::Persistent<Function>         constructor;
    ContextifyContext                   *ctx;
};

Nan::Persistent<FunctionTemplate> ContextWrap::functionTemplate;
Nan::Persistent<Function>         ContextWrap::constructor;

void ContextifyContext::Wrap(Local<Object> handle) {
    Nan::ObjectWrap::Wrap(handle);
    Local<Context> lcontext = ContextWrap::createV8Context(handle);
    context.Reset(lcontext);
    proxyGlobal.Reset(lcontext->Global());
}

class ContextifyScript : public Nan::ObjectWrap {
public:
    static Nan::Persistent<FunctionTemplate> scriptTmpl;
    Nan::Persistent<Nan::UnboundScript> script;

    static void Init(Local<Object> target) {
        Nan::HandleScope scope;

        Local<String> className = Nan::New("ContextifyScript").ToLocalChecked();

        Local<FunctionTemplate> lscriptTmpl = Nan::New<FunctionTemplate>(New);
        lscriptTmpl->InstanceTemplate()->SetInternalFieldCount(1);
        lscriptTmpl->SetClassName(className);

        Nan::SetPrototypeMethod(lscriptTmpl, "runInContext", RunInContext);

        scriptTmpl.Reset(lscriptTmpl);
        target->Set(className, lscriptTmpl->GetFunction());
    }
    static NAN_METHOD(New) {
        ContextifyScript *contextify_script = new ContextifyScript();
        contextify_script->Wrap(info.Holder());

        if (info.Length() < 1)
            return Nan::ThrowTypeError("needs at least 'code' argument.");

        Local<String> code = info[0]->ToString();

        Nan::TryCatch trycatch;

        Nan::MaybeLocal<String> filename = info.Length() > 1
                               ? info[1]->ToString()
                               : Nan::New("ContextifyScript.<anonymous>");

        if (filename.IsEmpty()) {
            trycatch.ReThrow();
            return;
        }

        Local<Context> context = Nan::GetCurrentContext();
        Context::Scope context_scope(context);

        ScriptOrigin origin(filename.ToLocalChecked());
        Nan::MaybeLocal<Nan::UnboundScript> v8_script = Nan::New<Nan::UnboundScript>(code, origin);

        if (v8_script.IsEmpty()) {
            trycatch.ReThrow();
            return;
        }

        contextify_script->script.Reset(v8_script.ToLocalChecked());

        info.GetReturnValue().Set(info.This());
    }

    static NAN_METHOD(RunInContext) {
        if (info.Length() == 0)
            return Nan::ThrowError("Must supply at least 1 argument to runInContext");

        if (!ContextifyContext::InstanceOf(info[0]->ToObject()))
            return Nan::ThrowTypeError("First argument must be a ContextifyContext.");

        ContextifyContext* ctx = Nan::ObjectWrap::Unwrap<ContextifyContext>(info[0]->ToObject());
        Local<Context> lcontext = Nan::New(ctx->context);

        Context::Scope scope(lcontext);

        ContextifyScript* wrapped_script = Nan::ObjectWrap::Unwrap<ContextifyScript>(info.This());
        Nan::MaybeLocal<Nan::UnboundScript> script = Nan::New(wrapped_script->script);

        Nan::TryCatch trycatch;

        if (script.IsEmpty()) {
            trycatch.ReThrow();
            return;
        }

        Nan::MaybeLocal<Value> result = Nan::RunScript(script.ToLocalChecked());

        if (result.IsEmpty()) {
            trycatch.ReThrow();
        } else {
            info.GetReturnValue().Set(result.ToLocalChecked());
        }
    }

    ~ContextifyScript() {
        script.Reset();
    }
};

Nan::Persistent<FunctionTemplate> ContextifyContext::jsTmpl;
Nan::Persistent<FunctionTemplate> ContextifyScript::scriptTmpl;

extern "C" {
    static void init(Local<Object> target) {
        ContextifyContext::Init(target);
        ContextifyScript::Init(target);
        ContextWrap::Init();
    }

    NODE_MODULE(contextify, init)
};
<commit_msg>Remove unnecessary include<commit_after>#include "nan.h"

using namespace v8;
using namespace node;

class ContextWrap;

class ContextifyContext : public Nan::ObjectWrap {
public:
    Nan::Persistent<Context> context;
    Nan::Persistent<Object>  sandbox;
    Nan::Persistent<Object>  proxyGlobal;

    static Nan::Persistent<FunctionTemplate> jsTmpl;

    ContextifyContext(Local<Object> sbox) {
        Nan::HandleScope scope;
        sandbox.Reset(sbox);
    }

    ~ContextifyContext() {
        context.Reset();
        proxyGlobal.Reset();
        sandbox.Reset();

        // Provide a GC hint that the context has gone away. Without this call it
        // does not seem that the collector will touch the context until under extreme
        // stress.
        Nan::ContextDisposedNotification();
    }

    // We override ObjectWrap::Wrap so that we can create our context after
    // we have a reference to our "host" JavaScript object.  If we try to use
    // handle_ in the ContextifyContext constructor, it will be empty since it's
    // set in ObjectWrap::Wrap.
    void Wrap(Local<Object> handle);

    static void Init(Local<Object> target) {
        Nan::HandleScope scope;

        Local<String> className = Nan::New("ContextifyContext").ToLocalChecked();

        Local<FunctionTemplate> ljsTmpl = Nan::New<FunctionTemplate>(New);
        ljsTmpl->InstanceTemplate()->SetInternalFieldCount(1);
        ljsTmpl->SetClassName(className);
        Nan::SetPrototypeMethod(ljsTmpl, "run",       ContextifyContext::Run);
        Nan::SetPrototypeMethod(ljsTmpl, "getGlobal", ContextifyContext::GetGlobal);

        jsTmpl.Reset(ljsTmpl);
        target->Set(className, ljsTmpl->GetFunction());
    }

    static NAN_METHOD(New) {
        if (info.Length() < 1)
            return Nan::ThrowError("Wrong number of arguments passed to ContextifyContext constructor");

        if (!info[0]->IsObject())
            return Nan::ThrowTypeError("Argument to ContextifyContext constructor must be an object.");

        ContextifyContext* ctx = new ContextifyContext(info[0]->ToObject());
        ctx->Wrap(info.This());
        info.GetReturnValue().Set(info.This());
    }

    static NAN_METHOD(Run) {
        if (info.Length() == 0)
            return Nan::ThrowError("Must supply at least 1 argument to run");

        if (!info[0]->IsString())
            return Nan::ThrowTypeError("First argument to run must be a String.");

        ContextifyContext* ctx = Nan::ObjectWrap::Unwrap<ContextifyContext>(info.This());
        Local<Context> lcontext = Nan::New(ctx->context);
        Context::Scope ctxScope(lcontext);
        Local<String> code = info[0]->ToString();

        Nan::TryCatch trycatch;
        Nan::MaybeLocal<Nan::BoundScript> script;

        if (info.Length() > 1 && info[1]->IsString()) {
            ScriptOrigin origin(info[1]->ToString());
            script = Nan::CompileScript(code, origin);
        } else {
            script = Nan::CompileScript(code);
        }

        if (script.IsEmpty()) {
            trycatch.ReThrow();
            return;
        }

        Nan::MaybeLocal<Value> result = Nan::RunScript(script.ToLocalChecked());

        if (result.IsEmpty()) {
            trycatch.ReThrow();
        } else {
            info.GetReturnValue().Set(result.ToLocalChecked());
        }
    }

    static bool InstanceOf(Local<Value> value) {
        return Nan::New(jsTmpl)->HasInstance(value);
    }

    static NAN_METHOD(GetGlobal) {
        ContextifyContext* ctx = Nan::ObjectWrap::Unwrap<ContextifyContext>(info.This());
        info.GetReturnValue().Set(Nan::New(ctx->proxyGlobal));
    }
};

// This is an object that just keeps an internal pointer to this
// ContextifyContext.  It's passed to the NamedPropertyHandler.  If we
// pass the main JavaScript context object we're embedded in, then the
// NamedPropertyHandler will store a reference to it forever and keep it
// from getting gc'd.
class ContextWrap : public Nan::ObjectWrap {
public:
    static void Init(void) {
        Nan::HandleScope scope;

        Local<FunctionTemplate> tmpl = Nan::New<FunctionTemplate>();
        tmpl->InstanceTemplate()->SetInternalFieldCount(1);
        functionTemplate.Reset(tmpl);
        constructor.Reset(tmpl->GetFunction());
    }

    static Local<Context> createV8Context(Local<Object> jsContextify) {
        Nan::EscapableHandleScope scope;
        Local<Object> wrapper = Nan::NewInstance(Nan::New(constructor)).ToLocalChecked();

        ContextWrap *contextWrapper = new ContextWrap();
        contextWrapper->Wrap(wrapper);

        Nan::Persistent<Object>(jsContextify).SetWeak(contextWrapper, &ContextWrap::weakCallback, Nan::WeakCallbackType::kParameter);
        contextWrapper->ctx = Nan::ObjectWrap::Unwrap<ContextifyContext>(jsContextify);

        Local<FunctionTemplate> ftmpl = Nan::New<FunctionTemplate>();
        ftmpl->SetHiddenPrototype(true);
        ftmpl->SetClassName(Nan::New(contextWrapper->ctx->sandbox)->GetConstructorName());
        Local<ObjectTemplate> otmpl = ftmpl->InstanceTemplate();
        Nan::SetNamedPropertyHandler(otmpl,
                                     GlobalPropertyGetter,
                                     GlobalPropertySetter,
                                     GlobalPropertyQuery,
                                     GlobalPropertyDeleter,
                                     GlobalPropertyEnumerator,
                                     wrapper);
#if NODE_MODULE_VERSION <= NODE_6_0_MODULE_VERSION
        otmpl->SetAccessCheckCallbacks(GlobalPropertyNamedAccessCheck,
                                       GlobalPropertyIndexedAccessCheck);
#else
        NamedPropertyHandlerConfiguration namedPropertyHandlerConfiguration;
        IndexedPropertyHandlerConfiguration indexedPropertyHandlerConfiguration;
        otmpl->SetAccessCheckCallbackAndHandler(AccessCheckCallback,
                                                namedPropertyHandlerConfiguration,
                                                indexedPropertyHandlerConfiguration);
#endif
        return scope.Escape(Nan::New<Context>(static_cast<ExtensionConfiguration*>(NULL), otmpl));
    }

private:
    ContextWrap() :ctx(NULL) {}

    ~ContextWrap() {
    }

#if NODE_MODULE_VERSION <= NODE_6_0_MODULE_VERSION
    static bool GlobalPropertyNamedAccessCheck(Local<Object> host,
                                               Local<Value>  key,
                                               AccessType    type,
                                               Local<Value>  data) {
        return true;
    }

    static bool GlobalPropertyIndexedAccessCheck(Local<Object> host,
                                                 uint32_t      key,
                                                 AccessType    type,
                                                 Local<Value>  data) {
        return true;
    }
#else
    static bool AccessCheckCallback(Local<Context> accessing_context,
                                    Local<Object> accessed_object,
                                    Local<Value> data) {
        return true;
    }
#endif

    static void GlobalPropertyGetter(Local<String> property, const Nan::PropertyCallbackInfo<Value>& info) {
        Local<Object> data = info.Data()->ToObject();
        ContextifyContext* ctx = Nan::ObjectWrap::Unwrap<ContextWrap>(data)->ctx;

        if (!ctx)
            return;

        Nan::MaybeLocal<Value> rv = Nan::GetRealNamedProperty(Nan::New(ctx->sandbox),
                                                              property);
        if (rv.IsEmpty())
            return;

        info.GetReturnValue().Set(rv.ToLocalChecked());
    }

    static void GlobalPropertySetter(Local<String> property, Local<Value> value, const Nan::PropertyCallbackInfo<Value>& info) {
        Local<Object> data = info.Data()->ToObject();
        ContextifyContext* ctx = Nan::ObjectWrap::Unwrap<ContextWrap>(data)->ctx;

        if (!ctx)
            return;

        Nan::New(ctx->sandbox)->Set(property, value);
        info.GetReturnValue().Set(value);
    }

    static void GlobalPropertyQuery(Local<String> property, const Nan::PropertyCallbackInfo<Integer>& info) {
        Local<Object> data = info.Data()->ToObject();
        ContextifyContext* ctx = Nan::ObjectWrap::Unwrap<ContextWrap>(data)->ctx;

        if (!ctx)
            return info.GetReturnValue().Set(Nan::New<Integer>(None));

        if (!Nan::GetRealNamedProperty(Nan::New(ctx->sandbox), property).IsEmpty() ||
            !Nan::GetRealNamedProperty(Nan::New(ctx->proxyGlobal), property).IsEmpty()) {
            info.GetReturnValue().Set(Nan::New<Integer>(None));
        } else {
            info.GetReturnValue().Set(Local<Integer>());
        }
    }

    static void GlobalPropertyDeleter(Local<String> property, const Nan::PropertyCallbackInfo<Boolean>& info) {
        Local<Object> data = info.Data()->ToObject();
        ContextifyContext* ctx = Nan::ObjectWrap::Unwrap<ContextWrap>(data)->ctx;

        if (!ctx)
            return info.GetReturnValue().Set(Nan::New(false));

        bool success = Nan::New(ctx->sandbox)->Delete(property);
        info.GetReturnValue().Set(Nan::New(success));
    }

    static void GlobalPropertyEnumerator(const Nan::PropertyCallbackInfo<Array>& info) {
        Local<Object> data = info.Data()->ToObject();
        ContextifyContext* ctx = Nan::ObjectWrap::Unwrap<ContextWrap>(data)->ctx;

        if (!ctx) {
            Local<Array> blank = Array::New(0);
            return info.GetReturnValue().Set(blank);
        }

        info.GetReturnValue().Set(Nan::New(ctx->sandbox)->GetPropertyNames());
    }

    static void weakCallback(const Nan::WeakCallbackInfo<ContextWrap>& data) {
        ContextWrap *self = data.GetParameter();
        self->ctx = NULL;
    }

    static Nan::Persistent<FunctionTemplate> functionTemplate;
    static Nan::Persistent<Function>         constructor;
    ContextifyContext                   *ctx;
};

Nan::Persistent<FunctionTemplate> ContextWrap::functionTemplate;
Nan::Persistent<Function>         ContextWrap::constructor;

void ContextifyContext::Wrap(Local<Object> handle) {
    Nan::ObjectWrap::Wrap(handle);
    Local<Context> lcontext = ContextWrap::createV8Context(handle);
    context.Reset(lcontext);
    proxyGlobal.Reset(lcontext->Global());
}

class ContextifyScript : public Nan::ObjectWrap {
public:
    static Nan::Persistent<FunctionTemplate> scriptTmpl;
    Nan::Persistent<Nan::UnboundScript> script;

    static void Init(Local<Object> target) {
        Nan::HandleScope scope;

        Local<String> className = Nan::New("ContextifyScript").ToLocalChecked();

        Local<FunctionTemplate> lscriptTmpl = Nan::New<FunctionTemplate>(New);
        lscriptTmpl->InstanceTemplate()->SetInternalFieldCount(1);
        lscriptTmpl->SetClassName(className);

        Nan::SetPrototypeMethod(lscriptTmpl, "runInContext", RunInContext);

        scriptTmpl.Reset(lscriptTmpl);
        target->Set(className, lscriptTmpl->GetFunction());
    }
    static NAN_METHOD(New) {
        ContextifyScript *contextify_script = new ContextifyScript();
        contextify_script->Wrap(info.Holder());

        if (info.Length() < 1)
            return Nan::ThrowTypeError("needs at least 'code' argument.");

        Local<String> code = info[0]->ToString();

        Nan::TryCatch trycatch;

        Nan::MaybeLocal<String> filename = info.Length() > 1
                               ? info[1]->ToString()
                               : Nan::New("ContextifyScript.<anonymous>");

        if (filename.IsEmpty()) {
            trycatch.ReThrow();
            return;
        }

        Local<Context> context = Nan::GetCurrentContext();
        Context::Scope context_scope(context);

        ScriptOrigin origin(filename.ToLocalChecked());
        Nan::MaybeLocal<Nan::UnboundScript> v8_script = Nan::New<Nan::UnboundScript>(code, origin);

        if (v8_script.IsEmpty()) {
            trycatch.ReThrow();
            return;
        }

        contextify_script->script.Reset(v8_script.ToLocalChecked());

        info.GetReturnValue().Set(info.This());
    }

    static NAN_METHOD(RunInContext) {
        if (info.Length() == 0)
            return Nan::ThrowError("Must supply at least 1 argument to runInContext");

        if (!ContextifyContext::InstanceOf(info[0]->ToObject()))
            return Nan::ThrowTypeError("First argument must be a ContextifyContext.");

        ContextifyContext* ctx = Nan::ObjectWrap::Unwrap<ContextifyContext>(info[0]->ToObject());
        Local<Context> lcontext = Nan::New(ctx->context);

        Context::Scope scope(lcontext);

        ContextifyScript* wrapped_script = Nan::ObjectWrap::Unwrap<ContextifyScript>(info.This());
        Nan::MaybeLocal<Nan::UnboundScript> script = Nan::New(wrapped_script->script);

        Nan::TryCatch trycatch;

        if (script.IsEmpty()) {
            trycatch.ReThrow();
            return;
        }

        Nan::MaybeLocal<Value> result = Nan::RunScript(script.ToLocalChecked());

        if (result.IsEmpty()) {
            trycatch.ReThrow();
        } else {
            info.GetReturnValue().Set(result.ToLocalChecked());
        }
    }

    ~ContextifyScript() {
        script.Reset();
    }
};

Nan::Persistent<FunctionTemplate> ContextifyContext::jsTmpl;
Nan::Persistent<FunctionTemplate> ContextifyScript::scriptTmpl;

extern "C" {
    static void init(Local<Object> target) {
        ContextifyContext::Init(target);
        ContextifyScript::Init(target);
        ContextWrap::Init();
    }

    NODE_MODULE(contextify, init)
};
<|endoftext|>


<commit_before>//
// vtTin3d.cpp
//
// Class which represents a Triangulated Irregular Network.
//
// Copyright (c) 2002 Virtual Terrain Project
// Free for all uses, see license.txt for details.
//

#include "vtlib/vtlib.h"
#include "vtTin3d.h"

vtTin3d::vtTin3d()
{
	m_pGeom = NULL;
	m_pDropGeom = NULL;
}

/**
 * Read the TIN from a file.  This can either be an old-style or new-style
 * .tin format (custom VTP format)
 */
bool vtTin3d::Read(const char *fname)
{
	if (!vtTin::Read(fname))
		return false;

	ComputeExtents();

	// set up the parent class (vtHeightField)
	Initialize(this);

	return true;
}

void vtTin3d::ComputeExtents()
{
	GetExtents(m_EarthExtents, m_fMinHeight, m_fMaxHeight);
}

FPoint3 ComputeNormal(const FPoint3 &p1, const FPoint3 &p2, const FPoint3 &p3)
{
	FPoint3 d1 = (p2 - p1);
	FPoint3 d2 = (p3 - p1);
	FPoint3 cross = d1.Cross(d2);
	cross.Normalize();
	return cross;
}

#define MAX_CHUNK_VERTS	30000

vtGeom *vtTin3d::CreateGeometry(bool bDropShadowMesh)
{
	// set up materials
	vtMaterialArray *pMats = new vtMaterialArray();
	bool lighting = false;
	pMats->AddRGBMaterial1(RGBf(1, 1, 1), false, lighting, false);
	pMats->AddRGBMaterial1(RGBf(0.5f, 0.5f, 0.5f), false, false, false);
	pMats->AddRGBMaterial1(RGBf(0, 0, 0), false, false, false);

	m_pGeom = new vtGeom();
	m_pGeom->SetMaterials(pMats);

	int i, j, k;
	int verts = NumVerts();

	// Break it up into a series of meshes - this is good for both
	// culling and memory management

	FPoint3 ep, wp;		// earth point, world point
	FPoint3 p[3], norm;
	FPoint3 light_dir(1, 1, 0);
	RGBf color;
	float r, g=1.0f, b=0.5f;

	// most TINs are larger in the horionztal dimension than the vertical, so
	// use horizontal extents as the basis of subdivision
	DRECT rect = m_EarthExtents;
	double sizex = rect.Width();
	double sizey = rect.Height();
	float height_range = (m_fMaxHeight - m_fMinHeight);

	// make it slightly larger avoid edge condition
	rect.left -= 0.000001;
	sizex += 0.000002;
	rect.bottom -= 0.000001;
	sizey += 0.000002;

	int divx, divy;		// number of x and y divisions
	int dsize;
	Bin *bins;
	int tris = NumTris();
	int bx, by;
	DPoint2 gp;

	int divs = 4;
	bool acceptable = false;
	while (!acceptable)
	{
		// take the smaller dimension and split in to ensure a minimum level
		// of subdivision, with the larger dimension proportional
		if (sizex < sizey)
		{
			divx = divs;
			divy = (int) (divx * sizey / sizex);
		}
		else
		{
			divy = divs;
			divx = (int) (divy * sizex / sizey);
		}

		// create a 2d array of Bins
		dsize = divx*divy;
		bins = new Bin[dsize];

		int most = -1, newsize;
		for (i = 0; i < tris; i++)
		{
			j = i * 3;
			gp = (m_vert[m_tri[j]] + m_vert[m_tri[j+1]] + m_vert[m_tri[j+2]]) / 3;
			bx = (int) (divx * (gp.x - rect.left) / sizex);
			by = (int) (divx * (gp.y - rect.bottom) / sizey);

			Bin &bref = bins[bx * divy + by];
			bref.Append(i);
			newsize = bref.GetSize();
			if (newsize > most)
				most = newsize;
		}
		if (most > 10000)
		{
			delete [] bins;
			divs = divs * 3 / 2;
		}
		else
			acceptable = true;
	}

	int in_bin, tri, vidx;

	for (i = 0; i < dsize; i++)
	{
		Bin &bref = bins[i];
		in_bin = bref.GetSize();
		if (!in_bin)
			continue;

		vtMesh *pMesh = new vtMesh(GL_TRIANGLES, VT_Normals|VT_Colors, in_bin * 3);

		for (j = 0; j < in_bin; j++)
		{
			tri = bref[j];
			int tribase = tri * 3;
			int vertbase = j * 3;

			for (k = 0; k < 3; k++)
			{
				vidx = m_tri[tribase + k];
				ep.Set(m_vert[vidx].x, m_vert[vidx].y, m_z[vidx]);
				m_Conversion.ConvertFromEarth(ep, p[k]);
			}
			norm = ComputeNormal(p[0], p[1], p[2]);

			float shade = norm.Dot(light_dir);	// shading 0 (dark) to 1 (light)

			for (k = 0; k < 3; k++)
			{
				vidx = m_tri[tribase + k];

				r = (m_z[vidx] - m_fMinHeight) / height_range;
				pMesh->AddVertex(p[k]);
				pMesh->SetVtxNormal(vertbase + k, norm);

				color.Set(r, g, b);
				color *= shade;
				pMesh->SetVtxColor(vertbase + k, color);
			}
		}
		m_pGeom->AddMesh(pMesh, 0);
		m_Meshes.Append(pMesh);
	}

	/*
	int base = 0;
	remaining = verts;
	while (remaining)
	{
		int chunk = remaining;
		if (chunk > MAX_CHUNK_VERTS)
			chunk = MAX_CHUNK_VERTS;
		int tris = chunk / 3;

		vtMesh *pMesh = new vtMesh(GL_TRIANGLES, VT_Normals|VT_Colors, chunk);

		for (i = 0; i < tris; i++)
		{
			for (j = 0; j < 3; j++)
				m_Conversion.ConvertFromEarth(m_vert[base + (i*3+j)], p[j]);
			norm = ComputeNormal(p[0], p[1], p[2]);

			float shade = norm.Dot(light_dir);	// shading 0 (dark) to 1 (light)

			for (j = 0; j < 3; j++)
			{
				r = (m_points[i*3+j].z - m_fMinHeight) / (m_fMaxHeight - m_fMinHeight);
				pMesh->AddVertex(p[j]);
				pMesh->SetVtxNormal(i*3+j, norm);

				color.Set(r, g, b);
				color *= shade;
				pMesh->SetVtxColor(i*3+j, color);
			}
		}
		m_pGeom->AddMesh(pMesh, 0);
		m_Meshes.Append(pMesh);

		if (bDropShadowMesh)
		{
			vtMesh *pShadowMesh = new vtMesh(GL_TRIANGLES, 0, chunk);
			for (i = 0; i < chunk; i++)
			{
				ep = m_points[base+i];
				ep.z = m_fMinHeight - 4.9;
				m_Conversion.ConvertFromEarth(ep, wp);
				pShadowMesh->AddVertex(wp);
			}
			m_pGeom->AddMesh(pShadowMesh, 2);
		}

		remaining -= chunk;
		base += chunk;
	}
		*/

	if (bDropShadowMesh)
	{
		vtMesh *pBaseMesh = new vtMesh(GL_TRIANGLE_FAN, 0, 4);

		ep.Set(m_EarthExtents.left - 10, m_EarthExtents.bottom - 10, m_fMinHeight - 5);
		m_Conversion.ConvertFromEarth(ep, wp);
		pBaseMesh->AddVertex(wp);

		ep.Set(m_EarthExtents.right + 10, m_EarthExtents.bottom - 10, m_fMinHeight - 5);
		m_Conversion.ConvertFromEarth(ep, wp);
		pBaseMesh->AddVertex(wp);

		ep.Set(m_EarthExtents.right + 10, m_EarthExtents.top + 10, m_fMinHeight - 5);
		m_Conversion.ConvertFromEarth(ep, wp);
		pBaseMesh->AddVertex(wp);

		ep.Set(m_EarthExtents.left - 10, m_EarthExtents.top + 10, m_fMinHeight - 5);
		m_Conversion.ConvertFromEarth(ep, wp);
		pBaseMesh->AddVertex(wp);

		pBaseMesh->AddFan(0, 1, 2, 3);
		m_pGeom->AddMesh(pBaseMesh, 1);
	}
	return m_pGeom;
}

bool vtTin3d::FindAltitudeAtPoint(const FPoint3 &input, float &fAltitude, FPoint3 *vNormal)
{
	// First try to identify which triangle
	FPoint2 p(input.x, input.z);

	FPoint3 wp1, wp2, wp3;
	FPoint2 p1, p2, p3;
	bool good;

	for (int m = 0; m < m_Meshes.GetSize(); m++)
	{
		vtMesh *mesh = m_Meshes[m];
		int tris = mesh->GetNumVertices() / 3;
		for (int i = 0; i < tris; i++)
		{
			// get world points
			wp1 = mesh->GetVtxPos(i*3+0);
			wp2 = mesh->GetVtxPos(i*3+1);
			wp3 = mesh->GetVtxPos(i*3+2);
			// convert to 2d
			p1.Set(wp1.x, wp1.z);
			p2.Set(wp2.x, wp2.z);
			p3.Set(wp3.x, wp3.z);

			if (!PointInTriangle(p, p1, p2, p3))
				continue;

			// compute barycentric coordinates with respect to the triangle
			float bary[3], val;
			good = BarycentricCoords(p1, p2, p3, p, bary);
			if (!good)
				continue;

			// compute barycentric combination of function values at vertices
			val = bary[0]*wp1.y +
				  bary[1]*wp2.y +
				  bary[2]*wp3.y;
			fAltitude = val;
			return true;
		}
	}
	return false;
}

/*
 * Algorithm from 'Fast, Minimum Storage Ray-Triangle Intersection',
 * Thomas Mller and Ben Trumbore, 1997
 * Adapted to use C++ and the vtdata math classes.
 */
#define EPSILON 0.000001
bool intersect_triangle(const FPoint3 &orig, const FPoint3 &dir,
			const FPoint3 &vert0, const FPoint3 &vert1, const FPoint3 &vert2,
			float &t, float &u, float &v)
{
	FPoint3 edge1, edge2, tvec, pvec, qvec;
	float det,inv_det;

	/* find vectors for two edges sharing vert0 */
	edge1 = vert1 - vert0;
	edge2 = vert2 - vert0;

	/* begin calculating determinant - also used to calculate U parameter */
	pvec = dir.Cross(edge2);

	/* if determinant is near zero, ray lies in plane of triangle */
	det = edge1.Dot(pvec);

	if (det < EPSILON)
		return false;

	/* calculate distance from vert0 to ray origin */
	tvec = orig - vert0;

	/* calculate U parameter and test bounds */
	u = tvec.Dot(pvec);
	if (u < 0.0 || u > det)
		return false;

	/* prepare to test V parameter */
	qvec = tvec.Cross(edge1);

	 /* calculate V parameter and test bounds */
	v = dir.Dot(qvec);
	if (v < 0.0 || u + v > det)
		return false;

	/* calculate t, scale parameters, ray intersects triangle */
	t = edge2.Dot(qvec);
	inv_det = 1.0 / det;
	t *= inv_det;
	u *= inv_det;
	v *= inv_det;

	return true;
}

bool vtTin3d::CastRayToSurface(const FPoint3 &point, const FPoint3 &dir, FPoint3 &result)
{
	FPoint3 wp1, wp2, wp3;
	float i, t, u, v, closest = 1E9;

	for (int m = 0; m < m_Meshes.GetSize(); m++)
	{
		vtMesh *mesh = m_Meshes[m];
		int tris = mesh->GetNumVertices() / 3;
		for (i = 0; i < tris; i++)
		{
			// get world points
			wp1 = mesh->GetVtxPos(i*3+0);
			wp2 = mesh->GetVtxPos(i*3+1);
			wp3 = mesh->GetVtxPos(i*3+2);
			if (intersect_triangle(point, dir, wp1, wp2, wp3, t, u, v))
			{
				if (t < closest)
					closest = t;
			}
		}
	}
	if (closest == 1E9)
		return false;

	result = point + (dir * closest);
	return true;
}

FPoint3 vtTin3d::FindVectorToClosestVertex(const FPoint3 &pos)
{
	FPoint3 vert, diff, closest_diff;
	float len, minlen = 1E9;

	for (int m = 0; m < m_Meshes.GetSize(); m++)
	{
		vtMesh *mesh = m_Meshes[m];
		int points = mesh->GetNumVertices();
		for (int i = 0; i < points; i++)
		{
			vert = mesh->GetVtxPos(i);
			diff = vert - pos;
			len = diff.Length();
			if (len < minlen)
			{
				minlen = len;
				closest_diff = diff;
			}
		}
	}
	return closest_diff;
}

<commit_msg>changed i to int<commit_after>//
// vtTin3d.cpp
//
// Class which represents a Triangulated Irregular Network.
//
// Copyright (c) 2002 Virtual Terrain Project
// Free for all uses, see license.txt for details.
//

#include "vtlib/vtlib.h"
#include "vtTin3d.h"

vtTin3d::vtTin3d()
{
	m_pGeom = NULL;
	m_pDropGeom = NULL;
}

/**
 * Read the TIN from a file.  This can either be an old-style or new-style
 * .tin format (custom VTP format)
 */
bool vtTin3d::Read(const char *fname)
{
	if (!vtTin::Read(fname))
		return false;

	ComputeExtents();

	// set up the parent class (vtHeightField)
	Initialize(this);

	return true;
}

void vtTin3d::ComputeExtents()
{
	GetExtents(m_EarthExtents, m_fMinHeight, m_fMaxHeight);
}

FPoint3 ComputeNormal(const FPoint3 &p1, const FPoint3 &p2, const FPoint3 &p3)
{
	FPoint3 d1 = (p2 - p1);
	FPoint3 d2 = (p3 - p1);
	FPoint3 cross = d1.Cross(d2);
	cross.Normalize();
	return cross;
}

#define MAX_CHUNK_VERTS	30000

vtGeom *vtTin3d::CreateGeometry(bool bDropShadowMesh)
{
	// set up materials
	vtMaterialArray *pMats = new vtMaterialArray();
	bool lighting = false;
	pMats->AddRGBMaterial1(RGBf(1, 1, 1), false, lighting, false);
	pMats->AddRGBMaterial1(RGBf(0.5f, 0.5f, 0.5f), false, false, false);
	pMats->AddRGBMaterial1(RGBf(0, 0, 0), false, false, false);

	m_pGeom = new vtGeom();
	m_pGeom->SetMaterials(pMats);

	int i, j, k;
	int verts = NumVerts();

	// Break it up into a series of meshes - this is good for both
	// culling and memory management

	FPoint3 ep, wp;		// earth point, world point
	FPoint3 p[3], norm;
	FPoint3 light_dir(1, 1, 0);
	RGBf color;
	float r, g=1.0f, b=0.5f;

	// most TINs are larger in the horionztal dimension than the vertical, so
	// use horizontal extents as the basis of subdivision
	DRECT rect = m_EarthExtents;
	double sizex = rect.Width();
	double sizey = rect.Height();
	float height_range = (m_fMaxHeight - m_fMinHeight);

	// make it slightly larger avoid edge condition
	rect.left -= 0.000001;
	sizex += 0.000002;
	rect.bottom -= 0.000001;
	sizey += 0.000002;

	int divx, divy;		// number of x and y divisions
	int dsize;
	Bin *bins;
	int tris = NumTris();
	int bx, by;
	DPoint2 gp;

	int divs = 4;
	bool acceptable = false;
	while (!acceptable)
	{
		// take the smaller dimension and split in to ensure a minimum level
		// of subdivision, with the larger dimension proportional
		if (sizex < sizey)
		{
			divx = divs;
			divy = (int) (divx * sizey / sizex);
		}
		else
		{
			divy = divs;
			divx = (int) (divy * sizex / sizey);
		}

		// create a 2d array of Bins
		dsize = divx*divy;
		bins = new Bin[dsize];

		int most = -1, newsize;
		for (i = 0; i < tris; i++)
		{
			j = i * 3;
			gp = (m_vert[m_tri[j]] + m_vert[m_tri[j+1]] + m_vert[m_tri[j+2]]) / 3;
			bx = (int) (divx * (gp.x - rect.left) / sizex);
			by = (int) (divx * (gp.y - rect.bottom) / sizey);

			Bin &bref = bins[bx * divy + by];
			bref.Append(i);
			newsize = bref.GetSize();
			if (newsize > most)
				most = newsize;
		}
		if (most > 10000)
		{
			delete [] bins;
			divs = divs * 3 / 2;
		}
		else
			acceptable = true;
	}

	int in_bin, tri, vidx;

	for (i = 0; i < dsize; i++)
	{
		Bin &bref = bins[i];
		in_bin = bref.GetSize();
		if (!in_bin)
			continue;

		vtMesh *pMesh = new vtMesh(GL_TRIANGLES, VT_Normals|VT_Colors, in_bin * 3);

		for (j = 0; j < in_bin; j++)
		{
			tri = bref[j];
			int tribase = tri * 3;
			int vertbase = j * 3;

			for (k = 0; k < 3; k++)
			{
				vidx = m_tri[tribase + k];
				ep.Set(m_vert[vidx].x, m_vert[vidx].y, m_z[vidx]);
				m_Conversion.ConvertFromEarth(ep, p[k]);
			}
			norm = ComputeNormal(p[0], p[1], p[2]);

			float shade = norm.Dot(light_dir);	// shading 0 (dark) to 1 (light)

			for (k = 0; k < 3; k++)
			{
				vidx = m_tri[tribase + k];

				r = (m_z[vidx] - m_fMinHeight) / height_range;
				pMesh->AddVertex(p[k]);
				pMesh->SetVtxNormal(vertbase + k, norm);

				color.Set(r, g, b);
				color *= shade;
				pMesh->SetVtxColor(vertbase + k, color);
			}
		}
		m_pGeom->AddMesh(pMesh, 0);
		m_Meshes.Append(pMesh);
	}

	/*
	int base = 0;
	remaining = verts;
	while (remaining)
	{
		int chunk = remaining;
		if (chunk > MAX_CHUNK_VERTS)
			chunk = MAX_CHUNK_VERTS;
		int tris = chunk / 3;

		vtMesh *pMesh = new vtMesh(GL_TRIANGLES, VT_Normals|VT_Colors, chunk);

		for (i = 0; i < tris; i++)
		{
			for (j = 0; j < 3; j++)
				m_Conversion.ConvertFromEarth(m_vert[base + (i*3+j)], p[j]);
			norm = ComputeNormal(p[0], p[1], p[2]);

			float shade = norm.Dot(light_dir);	// shading 0 (dark) to 1 (light)

			for (j = 0; j < 3; j++)
			{
				r = (m_points[i*3+j].z - m_fMinHeight) / (m_fMaxHeight - m_fMinHeight);
				pMesh->AddVertex(p[j]);
				pMesh->SetVtxNormal(i*3+j, norm);

				color.Set(r, g, b);
				color *= shade;
				pMesh->SetVtxColor(i*3+j, color);
			}
		}
		m_pGeom->AddMesh(pMesh, 0);
		m_Meshes.Append(pMesh);

		if (bDropShadowMesh)
		{
			vtMesh *pShadowMesh = new vtMesh(GL_TRIANGLES, 0, chunk);
			for (i = 0; i < chunk; i++)
			{
				ep = m_points[base+i];
				ep.z = m_fMinHeight - 4.9;
				m_Conversion.ConvertFromEarth(ep, wp);
				pShadowMesh->AddVertex(wp);
			}
			m_pGeom->AddMesh(pShadowMesh, 2);
		}

		remaining -= chunk;
		base += chunk;
	}
		*/

	if (bDropShadowMesh)
	{
		vtMesh *pBaseMesh = new vtMesh(GL_TRIANGLE_FAN, 0, 4);

		ep.Set(m_EarthExtents.left - 10, m_EarthExtents.bottom - 10, m_fMinHeight - 5);
		m_Conversion.ConvertFromEarth(ep, wp);
		pBaseMesh->AddVertex(wp);

		ep.Set(m_EarthExtents.right + 10, m_EarthExtents.bottom - 10, m_fMinHeight - 5);
		m_Conversion.ConvertFromEarth(ep, wp);
		pBaseMesh->AddVertex(wp);

		ep.Set(m_EarthExtents.right + 10, m_EarthExtents.top + 10, m_fMinHeight - 5);
		m_Conversion.ConvertFromEarth(ep, wp);
		pBaseMesh->AddVertex(wp);

		ep.Set(m_EarthExtents.left - 10, m_EarthExtents.top + 10, m_fMinHeight - 5);
		m_Conversion.ConvertFromEarth(ep, wp);
		pBaseMesh->AddVertex(wp);

		pBaseMesh->AddFan(0, 1, 2, 3);
		m_pGeom->AddMesh(pBaseMesh, 1);
	}
	return m_pGeom;
}

bool vtTin3d::FindAltitudeAtPoint(const FPoint3 &input, float &fAltitude, FPoint3 *vNormal)
{
	// First try to identify which triangle
	FPoint2 p(input.x, input.z);

	FPoint3 wp1, wp2, wp3;
	FPoint2 p1, p2, p3;
	bool good;

	for (int m = 0; m < m_Meshes.GetSize(); m++)
	{
		vtMesh *mesh = m_Meshes[m];
		int tris = mesh->GetNumVertices() / 3;
		for (int i = 0; i < tris; i++)
		{
			// get world points
			wp1 = mesh->GetVtxPos(i*3+0);
			wp2 = mesh->GetVtxPos(i*3+1);
			wp3 = mesh->GetVtxPos(i*3+2);
			// convert to 2d
			p1.Set(wp1.x, wp1.z);
			p2.Set(wp2.x, wp2.z);
			p3.Set(wp3.x, wp3.z);

			if (!PointInTriangle(p, p1, p2, p3))
				continue;

			// compute barycentric coordinates with respect to the triangle
			float bary[3], val;
			good = BarycentricCoords(p1, p2, p3, p, bary);
			if (!good)
				continue;

			// compute barycentric combination of function values at vertices
			val = bary[0]*wp1.y +
				  bary[1]*wp2.y +
				  bary[2]*wp3.y;
			fAltitude = val;
			return true;
		}
	}
	return false;
}

/*
 * Algorithm from 'Fast, Minimum Storage Ray-Triangle Intersection',
 * Thomas Mller and Ben Trumbore, 1997
 * Adapted to use C++ and the vtdata math classes.
 */
#define EPSILON 0.000001
bool intersect_triangle(const FPoint3 &orig, const FPoint3 &dir,
			const FPoint3 &vert0, const FPoint3 &vert1, const FPoint3 &vert2,
			float &t, float &u, float &v)
{
	FPoint3 edge1, edge2, tvec, pvec, qvec;
	float det,inv_det;

	/* find vectors for two edges sharing vert0 */
	edge1 = vert1 - vert0;
	edge2 = vert2 - vert0;

	/* begin calculating determinant - also used to calculate U parameter */
	pvec = dir.Cross(edge2);

	/* if determinant is near zero, ray lies in plane of triangle */
	det = edge1.Dot(pvec);

	if (det < EPSILON)
		return false;

	/* calculate distance from vert0 to ray origin */
	tvec = orig - vert0;

	/* calculate U parameter and test bounds */
	u = tvec.Dot(pvec);
	if (u < 0.0 || u > det)
		return false;

	/* prepare to test V parameter */
	qvec = tvec.Cross(edge1);

	 /* calculate V parameter and test bounds */
	v = dir.Dot(qvec);
	if (v < 0.0 || u + v > det)
		return false;

	/* calculate t, scale parameters, ray intersects triangle */
	t = edge2.Dot(qvec);
	inv_det = 1.0 / det;
	t *= inv_det;
	u *= inv_det;
	v *= inv_det;

	return true;
}

bool vtTin3d::CastRayToSurface(const FPoint3 &point, const FPoint3 &dir, FPoint3 &result)
{
	FPoint3 wp1, wp2, wp3;
	float t, u, v, closest = 1E9;
	int i;

	for (int m = 0; m < m_Meshes.GetSize(); m++)
	{
		vtMesh *mesh = m_Meshes[m];
		int tris = mesh->GetNumVertices() / 3;
		for (i = 0; i < tris; i++)
		{
			// get world points
			wp1 = mesh->GetVtxPos(i*3+0);
			wp2 = mesh->GetVtxPos(i*3+1);
			wp3 = mesh->GetVtxPos(i*3+2);
			if (intersect_triangle(point, dir, wp1, wp2, wp3, t, u, v))
			{
				if (t < closest)
					closest = t;
			}
		}
	}
	if (closest == 1E9)
		return false;

	result = point + (dir * closest);
	return true;
}

FPoint3 vtTin3d::FindVectorToClosestVertex(const FPoint3 &pos)
{
	FPoint3 vert, diff, closest_diff;
	float len, minlen = 1E9;

	for (int m = 0; m < m_Meshes.GetSize(); m++)
	{
		vtMesh *mesh = m_Meshes[m];
		int points = mesh->GetNumVertices();
		for (int i = 0; i < points; i++)
		{
			vert = mesh->GetVtxPos(i);
			diff = vert - pos;
			len = diff.Length();
			if (len < minlen)
			{
				minlen = len;
				closest_diff = diff;
			}
		}
	}
	return closest_diff;
}

<|endoftext|>


<commit_before>#include "igloo/igloo_alt.h"
#include "Landmarks.hh"
#include "test_data.hh"
#include "CustomConstraint.hh"

using namespace igloo;

/**
 * Unit test for Landmark constructor
 **/
When(creating_a_landmark)
{
  Then(it_should_have_default_value)
    {
      Assert::That(lm.id, Is().EqualTo(::Landmark_Result::id));
      Assert::That(lm.life, Is().EqualTo(::Landmark_Result::life));
      Assert::That(lm.totalTimeObserved, Is().EqualTo(::Landmark_Result::totalTimesObserved));
      Assert::That(lm.range, Is().EqualTo(::Landmark_Result::range));
      Assert::That(lm.bearing, Is().EqualTo(::Landmark_Result::bearing));
      Assert::That(lm.pos[0], Is().EqualTo(::Landmark_Result::pos[0]));
      Assert::That(lm.pos[1], Is().EqualTo(::Landmark_Result::pos[1]));
    }

  ::Landmarks::Landmark	lm;
};

/**
 * Unit test for default Landmarks constructor
 **/
When(creating_Landmarks)
{
  Then(it_should_have_default_landmarks_value)
  {
    Assert::That(lms.DBSize, Is().EqualTo(::Landmarks_Result::DBSize));
    Assert::That(lms.EKFLandmarks, Is().EqualTo(::Landmarks_Result::EKFLandmarks));
    Assert::That(lms.degreePerScan, Is().EqualTo(::Landmarks_Result::defaultdegreePerScan));
    Assert::That(lms.IDtoID.size(), Is().EqualTo(::Landmarks_Result::sizeIDtoID));
    Assert::That(lms.landmarkDB.size(), Is().EqualTo(::Landmarks_Result::sizelandmarkDB));
  }

  Landmarks lms;
};

/**
 * Unit test for specifi Landmarks constructor : Landmarks(double)
 **/
When(creating_Landmarks_with_a_specific_degree_value_different_from_default)
{
  void SetUp()
  {
    lms = new ::Landmarks(::Landmarks_Result::degreePerScan);
  }

  Then(it_should_not_have_default_degree_value)
  {
    Assert::That(lms->degreePerScan, Is().Not().EqualTo(::Landmarks_Result::defaultdegreePerScan));
  }

  Then(it_should_have_this_specific_degree_value)
  {
    Assert::That(lms->degreePerScan, Is().EqualTo(::Landmarks_Result::degreePerScan));
  }

  void	TearDown()
  {
    delete lms;
  }

  Landmarks *lms;
};

/**
 * Unit test for getDbSize() before any change
 */
When(calling_getDBSize_after_construct)
{

  Then(it_should_be_equal_to_DBSize_value)
  {
    Assert::That(lms.getDBSize(), Is().EqualTo(lms.DBSize));
  }

  Landmarks lms;
};

/**
 * Unit test for getDbSize() after change
 **/
When(calling_getDBSize_after_DBSize_changed)
{

  void	SetUp()
  {
    lms.DBSize += 1;
  }

  Then(it_should_be_equal_to_DBSize_value)
  {
    Assert::That(lms.getDBSize(), Is().EqualTo(lms.DBSize));
  }

  Landmarks lms;
};

/**
 * Unit test for addSlamId()
 **/
When(adding_one_Slam_Id)
{

  void	SetUp()
  {
    previousLandmarksNumber = lms.EKFLandmarks;
    lms.addSlamId(::Landmarks_Result::goodSlamId.first, ::Landmarks_Result::goodSlamId.second);
  }

  Then(it_should_increase_EKFLandmarks_by_one)
  {
    Assert::That(lms.EKFLandmarks, Is().EqualTo(previousLandmarksNumber + 1));
  }

  Then(it_should_be_the_good_id)
  {
    Assert::That(lms.IDtoID[previousLandmarksNumber].first, Is().EqualTo(::Landmarks_Result::goodSlamId.first));
    Assert::That(lms.IDtoID[previousLandmarksNumber].second, Is().EqualTo(::Landmarks_Result::goodSlamId.second));
  }

  Landmarks lms;
  int	previousLandmarksNumber;
};

/**
 * Unit test for getSlamId()
 **/
When(getting_Slam_Id)
{

  void	SetUp()
  {
    lms.addSlamId(::Landmarks_Result::wrongSlamId.first, ::Landmarks_Result::wrongSlamId.second);
    lms.addSlamId(::Landmarks_Result::goodSlamId.first, ::Landmarks_Result::goodSlamId.second);
  }

  Then(it_should_not_return_the_bad_id)
  {
    Assert::That(lms.getSLamId(::Landmarks_Result::goodSlamId.first),
		 Is().Not().EqualTo(::Landmarks_Result::wrongSlamId.second));
  }

  Then(it_should_return_the_good_id)
  {
    Assert::That(lms.getSLamId(::Landmarks_Result::goodSlamId.first),
		 Is().EqualTo(::Landmarks_Result::goodSlamId.second));
  }

  Landmarks lms;
};

/**
 * Unit test for addToDB()
 **/
When(adding_landmark_to_db)
{

  void	SetUp()
  {
    lm.pos[0] = ::Landmark_Result::pos[0] + 1;
    lm.pos[1] = ::Landmark_Result::pos[1] + 1;
    lm.life = LIFE - 1;
    lm.bearing = ::Landmark_Result::bearing + 1;
    lm.range = ::Landmark_Result::range + 1;
    lm.a = 3.12;
    lm.b = 4.52;

    previousDBSize = lms.DBSize;
    idLandmark = lms.addToDB(lm);
  }

  Then(DBSize_should_be_increased_by_one)
  {
    Assert::That(lms.DBSize, Is().EqualTo(previousDBSize + 1));
  }

  Then(it_have_the_good_landmark)
  {
    Assert::That(lms.landmarkDB[idLandmark]->pos[0], Is().EqualTo(lm.pos[0]));
    Assert::That(lms.landmarkDB[idLandmark]->pos[1], Is().EqualTo(lm.pos[1]));
    Assert::That(lms.landmarkDB[idLandmark]->bearing, Is().EqualTo(lm.bearing));
    Assert::That(lms.landmarkDB[idLandmark]->range, Is().EqualTo(lm.range));
    Assert::That(lms.landmarkDB[idLandmark]->a, Is().EqualTo(lm.a));
    Assert::That(lms.landmarkDB[idLandmark]->b, Is().EqualTo(lm.b));
    Assert::That(lms.landmarkDB[idLandmark]->life, Is().EqualTo(LIFE));
    Assert::That(lms.landmarkDB[idLandmark]->id, Is().EqualTo(idLandmark));
    Assert::That(lms.landmarkDB[idLandmark]->totalTimeObserved, Is().EqualTo(1));
  }

  Landmarks::Landmark	lm;
  Landmarks		lms;
  int			previousDBSize;
  int			idLandmark;
};

/**
 * Unit test for getLandmarkDb()
 **/
When(getting_LandmarkDB)
{

  void	SetUp()
  {
    id1 = lms.addToDB(lm1);
    id2 = lms.addToDB(lm2);
    db = lms.getLandmarkDB();
  }

  Then(it_should_hae_the_same_size)
  {
    Assert::That(db.size(), Is().EqualTo(lms.DBSize));
  }

  Then(it_should_have_the_same_elements)
  {
    for(int i = 0; i < lms.DBSize; ++i)
      {
	Assert::That(db[i], Fulfills(IsSameLandmark(lms.landmarkDB[i])));
      }
  }

  Then(it_should_be_a_copy)
  {
    double oldPos[2] = {lms.landmarkDB[id1]->pos[0], lms.landmarkDB[id1]->pos[1]};
    double oldRange = lms.landmarkDB[id1]->range;

    lms.landmarkDB[id1]->pos[0] = oldPos[0] + 1;
    lms.landmarkDB[id1]->range = oldRange + 1;

    Assert::That(db[id1], Is().Not().Fulfilling(IsSameLandmark(lms.landmarkDB[id1])));

    Assert::That(db[id1]->pos[0], Is().EqualTo(oldPos[0]));
    Assert::That(db[id1]->range, Is().EqualTo(oldRange));
  }

  Landmarks lms;
  Landmarks::Landmark lm1;
  Landmarks::Landmark lm2;
  std::vector<Landmarks::Landmark *> db;
  int	id1;
  int	id2;
};

/**
 * Unit test for getAssociation()
 **/
When(getting_association)
{

  void	SetUp()
  {
    lm1.pos[0] = 4.2;
    lm1.pos[1] = 2.4;
    id1 = lms.addToDB(lm1);
    id2 = lms.addToDB(lm2);
  }

  When(it_is_a_already_seen_landmark)
  {
    void	SetUp()
    {
      Root().oldTimeObserved =  Root().lms.landmarkDB[Root().id1]->totalTimeObserved;
      idGot = Root().lms.getAssociation(Root().lm1);
    }

    Then(it_should_update_good_landmark)
    {
      Assert::That(idGot, Is().EqualTo(Root().id1));
    }

    Then(it_should_increase_time_observed)
    {
      Assert::That(Root().lms.landmarkDB[Root().id1]->totalTimeObserved,
		   Is().EqualTo(Root().oldTimeObserved + 1));
    }

    Then(it_should_reset_life_counter)
    {
      Assert::That(Root().lms.landmarkDB[Root().id1]->life, Is().EqualTo(LIFE));
    }
    int	idGot;
  };

  When(it_is_a_never_seen_landmark)
  {
    void	SetUp()
    {
      Root().lm2.pos[0] = 10;
      Root().lm2.pos[1] = 8;
      Root().oldTimeObserved = Root().lms.landmarkDB[Root().id2]->totalTimeObserved;
    }

    Then(it_should_not_update)
    {
      Assert::That(Root().lms.getAssociation(Root().lm2), Is().EqualTo(-1));
      Assert::That(Root().lms.landmarkDB[Root().id1]->totalTimeObserved,
		   Is().EqualTo(Root().oldTimeObserved));
    }
  };

  Landmarks lms;
  Landmarks::Landmark lm1;
  Landmarks::Landmark lm2;
  int	id1;
  int	id2;
  int	oldTimeObserved;
};

/**
 * Unit test for getClosestAssociation()
 **/
When(getting_closest_association_landmark)
{
  void	SetUp()
  {
    lm1.pos[0] = 24;
    lm1.pos[1] = 42;
    lm2.pos[0] = 10;
    lm2.pos[1] = 8;
    lm3.pos[0] = 12;
    lm3.pos[1] = 8;
    timeObservedResult = 0;
  }

  When(there_are_no_landmark)
  {
    void	SetUp()
    {
      Root().oldTimeObserved = Root().timeObservedResult;
      Root().lms.getClosestAssociation(&(Root().lm1), Root().idResult, Root().timeObservedResult);
    }

    Then(it_should_set_id_to_minus_one)
    {
      Assert::That(Root().idResult, Is().EqualTo(-1));
    }

    Then(it_should_not_change_total_time_observed)
    {
      Assert::That(Root().timeObservedResult, Is().EqualTo(Root().oldTimeObserved));
    }
  };

  Landmarks		lms;
  Landmarks::Landmark	lm1;
  Landmarks::Landmark	lm2;
  Landmarks::Landmark	lm3;
  int		id1;
  int		id2;
  int		idResult;
  int		timeObservedResult;
  int		oldTimeObserved;
};
<commit_msg>SLAM: TEST: getClosestAssociation(): Test with one landmark without enough observation<commit_after>#include "igloo/igloo_alt.h"
#include "Landmarks.hh"
#include "test_data.hh"
#include "CustomConstraint.hh"

using namespace igloo;

/**
 * Unit test for Landmark constructor
 **/
When(creating_a_landmark)
{
  Then(it_should_have_default_value)
    {
      Assert::That(lm.id, Is().EqualTo(::Landmark_Result::id));
      Assert::That(lm.life, Is().EqualTo(::Landmark_Result::life));
      Assert::That(lm.totalTimeObserved, Is().EqualTo(::Landmark_Result::totalTimesObserved));
      Assert::That(lm.range, Is().EqualTo(::Landmark_Result::range));
      Assert::That(lm.bearing, Is().EqualTo(::Landmark_Result::bearing));
      Assert::That(lm.pos[0], Is().EqualTo(::Landmark_Result::pos[0]));
      Assert::That(lm.pos[1], Is().EqualTo(::Landmark_Result::pos[1]));
    }

  ::Landmarks::Landmark	lm;
};

/**
 * Unit test for default Landmarks constructor
 **/
When(creating_Landmarks)
{
  Then(it_should_have_default_landmarks_value)
  {
    Assert::That(lms.DBSize, Is().EqualTo(::Landmarks_Result::DBSize));
    Assert::That(lms.EKFLandmarks, Is().EqualTo(::Landmarks_Result::EKFLandmarks));
    Assert::That(lms.degreePerScan, Is().EqualTo(::Landmarks_Result::defaultdegreePerScan));
    Assert::That(lms.IDtoID.size(), Is().EqualTo(::Landmarks_Result::sizeIDtoID));
    Assert::That(lms.landmarkDB.size(), Is().EqualTo(::Landmarks_Result::sizelandmarkDB));
  }

  Landmarks lms;
};

/**
 * Unit test for specifi Landmarks constructor : Landmarks(double)
 **/
When(creating_Landmarks_with_a_specific_degree_value_different_from_default)
{
  void SetUp()
  {
    lms = new ::Landmarks(::Landmarks_Result::degreePerScan);
  }

  Then(it_should_not_have_default_degree_value)
  {
    Assert::That(lms->degreePerScan, Is().Not().EqualTo(::Landmarks_Result::defaultdegreePerScan));
  }

  Then(it_should_have_this_specific_degree_value)
  {
    Assert::That(lms->degreePerScan, Is().EqualTo(::Landmarks_Result::degreePerScan));
  }

  void	TearDown()
  {
    delete lms;
  }

  Landmarks *lms;
};

/**
 * Unit test for getDbSize() before any change
 */
When(calling_getDBSize_after_construct)
{

  Then(it_should_be_equal_to_DBSize_value)
  {
    Assert::That(lms.getDBSize(), Is().EqualTo(lms.DBSize));
  }

  Landmarks lms;
};

/**
 * Unit test for getDbSize() after change
 **/
When(calling_getDBSize_after_DBSize_changed)
{

  void	SetUp()
  {
    lms.DBSize += 1;
  }

  Then(it_should_be_equal_to_DBSize_value)
  {
    Assert::That(lms.getDBSize(), Is().EqualTo(lms.DBSize));
  }

  Landmarks lms;
};

/**
 * Unit test for addSlamId()
 **/
When(adding_one_Slam_Id)
{

  void	SetUp()
  {
    previousLandmarksNumber = lms.EKFLandmarks;
    lms.addSlamId(::Landmarks_Result::goodSlamId.first, ::Landmarks_Result::goodSlamId.second);
  }

  Then(it_should_increase_EKFLandmarks_by_one)
  {
    Assert::That(lms.EKFLandmarks, Is().EqualTo(previousLandmarksNumber + 1));
  }

  Then(it_should_be_the_good_id)
  {
    Assert::That(lms.IDtoID[previousLandmarksNumber].first, Is().EqualTo(::Landmarks_Result::goodSlamId.first));
    Assert::That(lms.IDtoID[previousLandmarksNumber].second, Is().EqualTo(::Landmarks_Result::goodSlamId.second));
  }

  Landmarks lms;
  int	previousLandmarksNumber;
};

/**
 * Unit test for getSlamId()
 **/
When(getting_Slam_Id)
{

  void	SetUp()
  {
    lms.addSlamId(::Landmarks_Result::wrongSlamId.first, ::Landmarks_Result::wrongSlamId.second);
    lms.addSlamId(::Landmarks_Result::goodSlamId.first, ::Landmarks_Result::goodSlamId.second);
  }

  Then(it_should_not_return_the_bad_id)
  {
    Assert::That(lms.getSLamId(::Landmarks_Result::goodSlamId.first),
		 Is().Not().EqualTo(::Landmarks_Result::wrongSlamId.second));
  }

  Then(it_should_return_the_good_id)
  {
    Assert::That(lms.getSLamId(::Landmarks_Result::goodSlamId.first),
		 Is().EqualTo(::Landmarks_Result::goodSlamId.second));
  }

  Landmarks lms;
};

/**
 * Unit test for addToDB()
 **/
When(adding_landmark_to_db)
{

  void	SetUp()
  {
    lm.pos[0] = ::Landmark_Result::pos[0] + 1;
    lm.pos[1] = ::Landmark_Result::pos[1] + 1;
    lm.life = LIFE - 1;
    lm.bearing = ::Landmark_Result::bearing + 1;
    lm.range = ::Landmark_Result::range + 1;
    lm.a = 3.12;
    lm.b = 4.52;

    previousDBSize = lms.DBSize;
    idLandmark = lms.addToDB(lm);
  }

  Then(DBSize_should_be_increased_by_one)
  {
    Assert::That(lms.DBSize, Is().EqualTo(previousDBSize + 1));
  }

  Then(it_have_the_good_landmark)
  {
    Assert::That(lms.landmarkDB[idLandmark]->pos[0], Is().EqualTo(lm.pos[0]));
    Assert::That(lms.landmarkDB[idLandmark]->pos[1], Is().EqualTo(lm.pos[1]));
    Assert::That(lms.landmarkDB[idLandmark]->bearing, Is().EqualTo(lm.bearing));
    Assert::That(lms.landmarkDB[idLandmark]->range, Is().EqualTo(lm.range));
    Assert::That(lms.landmarkDB[idLandmark]->a, Is().EqualTo(lm.a));
    Assert::That(lms.landmarkDB[idLandmark]->b, Is().EqualTo(lm.b));
    Assert::That(lms.landmarkDB[idLandmark]->life, Is().EqualTo(LIFE));
    Assert::That(lms.landmarkDB[idLandmark]->id, Is().EqualTo(idLandmark));
    Assert::That(lms.landmarkDB[idLandmark]->totalTimeObserved, Is().EqualTo(1));
  }

  Landmarks::Landmark	lm;
  Landmarks		lms;
  int			previousDBSize;
  int			idLandmark;
};

/**
 * Unit test for getLandmarkDb()
 **/
When(getting_LandmarkDB)
{

  void	SetUp()
  {
    id1 = lms.addToDB(lm1);
    id2 = lms.addToDB(lm2);
    db = lms.getLandmarkDB();
  }

  Then(it_should_hae_the_same_size)
  {
    Assert::That(db.size(), Is().EqualTo(lms.DBSize));
  }

  Then(it_should_have_the_same_elements)
  {
    for(int i = 0; i < lms.DBSize; ++i)
      {
	Assert::That(db[i], Fulfills(IsSameLandmark(lms.landmarkDB[i])));
      }
  }

  Then(it_should_be_a_copy)
  {
    double oldPos[2] = {lms.landmarkDB[id1]->pos[0], lms.landmarkDB[id1]->pos[1]};
    double oldRange = lms.landmarkDB[id1]->range;

    lms.landmarkDB[id1]->pos[0] = oldPos[0] + 1;
    lms.landmarkDB[id1]->range = oldRange + 1;

    Assert::That(db[id1], Is().Not().Fulfilling(IsSameLandmark(lms.landmarkDB[id1])));

    Assert::That(db[id1]->pos[0], Is().EqualTo(oldPos[0]));
    Assert::That(db[id1]->range, Is().EqualTo(oldRange));
  }

  Landmarks lms;
  Landmarks::Landmark lm1;
  Landmarks::Landmark lm2;
  std::vector<Landmarks::Landmark *> db;
  int	id1;
  int	id2;
};

/**
 * Unit test for getAssociation()
 **/
When(getting_association)
{

  void	SetUp()
  {
    lm1.pos[0] = 4.2;
    lm1.pos[1] = 2.4;
    id1 = lms.addToDB(lm1);
    id2 = lms.addToDB(lm2);
  }

  When(it_is_a_already_seen_landmark)
  {
    void	SetUp()
    {
      Root().oldTimeObserved =  Root().lms.landmarkDB[Root().id1]->totalTimeObserved;
      idGot = Root().lms.getAssociation(Root().lm1);
    }

    Then(it_should_update_good_landmark)
    {
      Assert::That(idGot, Is().EqualTo(Root().id1));
    }

    Then(it_should_increase_time_observed)
    {
      Assert::That(Root().lms.landmarkDB[Root().id1]->totalTimeObserved,
		   Is().EqualTo(Root().oldTimeObserved + 1));
    }

    Then(it_should_reset_life_counter)
    {
      Assert::That(Root().lms.landmarkDB[Root().id1]->life, Is().EqualTo(LIFE));
    }
    int	idGot;
  };

  When(it_is_a_never_seen_landmark)
  {
    void	SetUp()
    {
      Root().lm2.pos[0] = 10;
      Root().lm2.pos[1] = 8;
      Root().oldTimeObserved = Root().lms.landmarkDB[Root().id2]->totalTimeObserved;
    }

    Then(it_should_not_update)
    {
      Assert::That(Root().lms.getAssociation(Root().lm2), Is().EqualTo(-1));
      Assert::That(Root().lms.landmarkDB[Root().id1]->totalTimeObserved,
		   Is().EqualTo(Root().oldTimeObserved));
    }
  };

  Landmarks lms;
  Landmarks::Landmark lm1;
  Landmarks::Landmark lm2;
  int	id1;
  int	id2;
  int	oldTimeObserved;
};

/**
 * Unit test for getClosestAssociation()
 **/
When(getting_closest_association_landmark)
{
  void	SetUp()
  {
    lm1.pos[0] = 24;
    lm1.pos[1] = 42;
    lm2.pos[0] = 10;
    lm2.pos[1] = 8;
    lm3.pos[0] = 12;
    lm3.pos[1] = 8;
    timeObservedResult = 0;
  }

  When(there_are_no_landmark)
  {
    void	SetUp()
    {
      Root().oldTimeObserved = Root().timeObservedResult;
      Root().lms.getClosestAssociation(&(Root().lm1), Root().idResult, Root().timeObservedResult);
    }

    Then(it_should_set_id_to_minus_one)
    {
      Assert::That(Root().idResult, Is().EqualTo(-1));
    }

    Then(it_should_not_change_total_time_observed)
    {
      Assert::That(Root().timeObservedResult, Is().EqualTo(Root().oldTimeObserved));
    }
  };

  When(there_is_one_landmark_with_not_enough_observation)
  {
    void	SetUp()
    {
      Root().lm1.totalTimeObserved = 1;
      Root().id1 = Root().lms.addToDB(Root().lm1);
      Root().oldTimeObserved = Root().timeObservedResult;
      Root().lms.getClosestAssociation(&(Root().lm1), Root().idResult, Root().timeObservedResult);
    }

    Then(it_should_set_id_to_landmark_id)
    {
      Assert::That(Root().idResult, Is().EqualTo(-1));
    }

    Then(it_should_change_total_time_observed)
    {
      Assert::That(Root().timeObservedResult, Is().EqualTo(Root().oldTimeObserved));
    }
 };

  Landmarks		lms;
  Landmarks::Landmark	lm1;
  Landmarks::Landmark	lm2;
  Landmarks::Landmark	lm3;
  int		id1;
  int		id2;
  int		idResult;
  int		timeObservedResult;
  int		oldTimeObserved;
};
<|endoftext|>


<commit_before>#include "Model1Feature.h"
#include "moses/StaticData.h"
#include "moses/InputFileStream.h"
#include "moses/ScoreComponentCollection.h"
#include "moses/FactorCollection.h"

using namespace std;

namespace Moses
{

const std::string Model1Vocabulary::GIZANULL = "GIZANULL";

Model1Vocabulary::Model1Vocabulary()
{
  FactorCollection &factorCollection = FactorCollection::Instance();
  m_NULL = factorCollection.AddFactor(GIZANULL,false);
  Store(m_NULL,0);
}

bool Model1Vocabulary::Store(const Factor* word, const unsigned id)
{
  boost::unordered_map<const Factor*, unsigned>::iterator iter = m_lookup.find( word );
  if ( iter != m_lookup.end() ) {
    return false;
  }
  m_lookup[ word ] = id;
  if ( m_vocab.size() <= id ) {
    m_vocab.resize(id+1);
  }
  m_vocab[id] = word;
  return true;
}

unsigned Model1Vocabulary::StoreIfNew(const Factor* word)
{
  boost::unordered_map<const Factor*, unsigned>::iterator iter = m_lookup.find( word );

  if ( iter != m_lookup.end() ) {
    return iter->second;
  }

  unsigned id = m_vocab.size();
  m_vocab.push_back( word );
  m_lookup[ word ] = id;
  return id;
}

unsigned Model1Vocabulary::GetWordID(const Factor* word) const
{
  boost::unordered_map<const Factor*, unsigned>::const_iterator iter = m_lookup.find( word );
  if ( iter == m_lookup.end() ) {
    return INVALID_ID;
  }
  return iter->second;
}

const Factor* Model1Vocabulary::GetWord(unsigned id) const
{
  if (id >= m_vocab.size()) {
    return NULL;
  }
  return m_vocab[ id ];
}

void Model1Vocabulary::Load(const std::string& fileName)
{
  InputFileStream inFile(fileName);
  FactorCollection &factorCollection = FactorCollection::Instance();
  std::string line;

  unsigned i = 0;
  if ( getline(inFile, line) ) { // first line of MGIZA vocabulary files seems to be special : "1       UNK     0"  -- skip if it's this
    ++i;
    std::vector<std::string> tokens = Tokenize(line);
    UTIL_THROW_IF2(tokens.size()!=3, "Line " << i << " in " << fileName << " has wrong number of tokens.");
    unsigned id = atoll( tokens[0].c_str() );
    if (! ( (id == 1) && (tokens[1] == "UNK") )) {
      const Factor* factor = factorCollection.AddFactor(tokens[1],false); // TODO: can we assume that the vocabulary is know and filter the model on loading?
      bool stored = Store(factor, id);
      UTIL_THROW_IF2(!stored, "Line " << i << " in " << fileName << " overwrites existing vocabulary entry.");
    }
  }
  while ( getline(inFile, line) ) {
    ++i;
    std::vector<std::string> tokens = Tokenize(line);
    UTIL_THROW_IF2(tokens.size()!=3, "Line " << i << " in " << fileName << " has wrong number of tokens.");
    unsigned id = atoll( tokens[0].c_str() );
    const Factor* factor = factorCollection.AddFactor(tokens[1],false); // TODO: can we assume that the vocabulary is know and filter the model on loading?
    bool stored = Store(factor, id);
    UTIL_THROW_IF2(!stored, "Line " << i << " in " << fileName << " overwrites existing vocabulary entry.");
  }
  inFile.Close();
}

void Model1LexicalTable::Load(const std::string &fileName, const Model1Vocabulary& vcbS, const Model1Vocabulary& vcbT)
{
  InputFileStream inFile(fileName);
  std::string line;

  unsigned i = 0;
  while ( getline(inFile, line) ) {
    ++i;
    std::vector<std::string> tokens = Tokenize(line);
    UTIL_THROW_IF2(tokens.size()!=3, "Line " << i << " in " << fileName << " has wrong number of tokens.");
    unsigned idS = atoll( tokens[0].c_str() );
    unsigned idT = atoll( tokens[1].c_str() );
    const Factor* wordS = vcbS.GetWord(idS);
    const Factor* wordT = vcbT.GetWord(idT);
    float prob = std::atof( tokens[2].c_str() );
    if ( (wordS != NULL) && (wordT != NULL) ) {
      m_ltable[ wordS ][ wordT ] = prob;
    }
    UTIL_THROW_IF2((wordS == NULL) || (wordT == NULL), "Line " << i << " in " << fileName << " has unknown vocabulary."); // TODO: can we assume that the vocabulary is know and filter the model on loading? Then remove this line.
  }
  inFile.Close();
}

// p( wordT | wordS )
float Model1LexicalTable::GetProbability(const Factor* wordS, const Factor* wordT) const
{
  float prob = m_floor;

  boost::unordered_map< const Factor*, boost::unordered_map< const Factor*, float > >::const_iterator iter1 = m_ltable.find( wordS );

  if ( iter1 != m_ltable.end() ) {
    boost::unordered_map< const Factor*, float >::const_iterator iter2 = iter1->second.find( wordT );
    if ( iter2 != iter1->second.end() ) {
      prob = iter2->second;
      if ( prob < m_floor ) {
        prob = m_floor;
      }
    }
  }
  return prob;
}

Model1Feature::Model1Feature(const std::string &line)
  : StatelessFeatureFunction(1, line)
  , m_is_syntax(false)
{
  VERBOSE(1, "Initializing feature " << GetScoreProducerDescription() << " ...");
  ReadParameters();
  VERBOSE(1, " Done.");
}

void Model1Feature::SetParameter(const std::string& key, const std::string& value)
{
  if (key == "path") {
    m_fileNameModel1 = value;
  } else if (key == "source-vocabulary") {
    m_fileNameVcbS = value;
  } else if (key == "target-vocabulary") {
    m_fileNameVcbT = value;
  } else {
    StatelessFeatureFunction::SetParameter(key, value);
  }
}

void Model1Feature::Load(AllOptions::ptr const& opts)
{
  m_options = opts;
  m_is_syntax = is_syntax(opts->search.algo);

  FEATUREVERBOSE(2, GetScoreProducerDescription() << ": Loading source vocabulary from file " << m_fileNameVcbS << " ...");
  Model1Vocabulary vcbS;
  vcbS.Load(m_fileNameVcbS);
  FEATUREVERBOSE2(2, " Done." << std::endl);
  FEATUREVERBOSE(2, GetScoreProducerDescription() << ": Loading target vocabulary from file " << m_fileNameVcbT << " ...");
  Model1Vocabulary vcbT;
  vcbT.Load(m_fileNameVcbT);
  FEATUREVERBOSE2(2, " Done." << std::endl);
  FEATUREVERBOSE(2, GetScoreProducerDescription() << ": Loading model 1 lexical translation table from file " << m_fileNameModel1 << " ...");
  m_model1.Load(m_fileNameModel1,vcbS,vcbT);
  FEATUREVERBOSE2(2, " Done." << std::endl);
  FactorCollection &factorCollection = FactorCollection::Instance();
  m_emptyWord = factorCollection.GetFactor(Model1Vocabulary::GIZANULL,false);
  UTIL_THROW_IF2(m_emptyWord==NULL, GetScoreProducerDescription()
                 << ": Factor for GIZA empty word does not exist.");

  const std::string punctuation = ",;.:!?";
  for (size_t i=0; i<punctuation.size(); ++i) {
    const std::string punct = punctuation.substr(i,1);
    FactorCollection &factorCollection = FactorCollection::Instance();
    const Factor* punctFactor = factorCollection.AddFactor(punct,false);
    std::pair<std::set<const Factor*>::iterator,bool> inserted = m_punctuation.insert(punctFactor);
  }
}

void Model1Feature::EvaluateWithSourceContext(const InputType &input
    , const InputPath &inputPath
    , const TargetPhrase &targetPhrase
    , const StackVec *stackVec
    , ScoreComponentCollection &scoreBreakdown
    , ScoreComponentCollection *estimatedScores) const
{
  const Sentence& sentence = static_cast<const Sentence&>(input);
  float score = 0.0;
  float norm = TransformScore(1+sentence.GetSize());

  for (size_t posT=0; posT<targetPhrase.GetSize(); ++posT) {
    const Word &wordT = targetPhrase.GetWord(posT);
    std::set<const Factor*>::const_iterator foundPunctuation = m_punctuation.find(wordT[0]);
    if (foundPunctuation != m_punctuation.end()) {
      continue;
    }
    if ( !wordT.IsNonTerminal() ) {
      float thisWordProb = m_model1.GetProbability(m_emptyWord,wordT[0]); // probability conditioned on empty word

      // cache lookup
      bool foundInCache = false;
      {
#ifdef WITH_THREADS
        boost::shared_lock<boost::shared_mutex> read_lock(m_accessLock);
#endif
        boost::unordered_map<const InputType*, boost::unordered_map<const Factor*, float> >::const_iterator sentenceCache = m_cache.find(&input);
        if (sentenceCache != m_cache.end()) {
          boost::unordered_map<const Factor*, float>::const_iterator cacheHit = sentenceCache->second.find(wordT[0]);
          if (cacheHit != sentenceCache->second.end()) {
            foundInCache = true;
            score += cacheHit->second;
            FEATUREVERBOSE(3, "Cached score( " << wordT << " ) = " << cacheHit->second << std::endl);
          }
        }
      }

      if (!foundInCache) {
        for (size_t posS=(m_is_syntax?1:0); posS<(m_is_syntax?sentence.GetSize()-1:sentence.GetSize()); ++posS) { // ignore <s> and </s>
          const Word &wordS = sentence.GetWord(posS);
          float modelProb = m_model1.GetProbability(wordS[0],wordT[0]);
          FEATUREVERBOSE(4, "p( " << wordT << " | " << wordS << " ) = " << modelProb << std::endl);
          thisWordProb += modelProb;
        }
        float thisWordScore = TransformScore(thisWordProb) - norm;
        FEATUREVERBOSE(3, "score( " << wordT << " ) = " << thisWordScore << std::endl);
        {
#ifdef WITH_THREADS
          // need to update cache; write lock
          boost::unique_lock<boost::shared_mutex> lock(m_accessLock);
#endif
          m_cache[&input][wordT[0]] = thisWordScore;
        }
        score += thisWordScore;
      }
    }
  }

  scoreBreakdown.PlusEquals(this, score);
}

void Model1Feature::CleanUpAfterSentenceProcessing(const InputType& source)
{
#ifdef WITH_THREADS
  // need to update cache; write lock
  boost::unique_lock<boost::shared_mutex> lock(m_accessLock);
#endif
  // clear cache
  boost::unordered_map<const InputType*, boost::unordered_map<const Factor*, float> >::iterator sentenceCache = m_cache.find(&source);
  if (sentenceCache != m_cache.end()) {
    sentenceCache->second.clear();
    m_cache.erase(sentenceCache);
  }
}

}

<commit_msg>daily automatic beautifier<commit_after>#include "Model1Feature.h"
#include "moses/StaticData.h"
#include "moses/InputFileStream.h"
#include "moses/ScoreComponentCollection.h"
#include "moses/FactorCollection.h"

using namespace std;

namespace Moses
{

const std::string Model1Vocabulary::GIZANULL = "GIZANULL";

Model1Vocabulary::Model1Vocabulary()
{
  FactorCollection &factorCollection = FactorCollection::Instance();
  m_NULL = factorCollection.AddFactor(GIZANULL,false);
  Store(m_NULL,0);
}

bool Model1Vocabulary::Store(const Factor* word, const unsigned id)
{
  boost::unordered_map<const Factor*, unsigned>::iterator iter = m_lookup.find( word );
  if ( iter != m_lookup.end() ) {
    return false;
  }
  m_lookup[ word ] = id;
  if ( m_vocab.size() <= id ) {
    m_vocab.resize(id+1);
  }
  m_vocab[id] = word;
  return true;
}

unsigned Model1Vocabulary::StoreIfNew(const Factor* word)
{
  boost::unordered_map<const Factor*, unsigned>::iterator iter = m_lookup.find( word );

  if ( iter != m_lookup.end() ) {
    return iter->second;
  }

  unsigned id = m_vocab.size();
  m_vocab.push_back( word );
  m_lookup[ word ] = id;
  return id;
}

unsigned Model1Vocabulary::GetWordID(const Factor* word) const
{
  boost::unordered_map<const Factor*, unsigned>::const_iterator iter = m_lookup.find( word );
  if ( iter == m_lookup.end() ) {
    return INVALID_ID;
  }
  return iter->second;
}

const Factor* Model1Vocabulary::GetWord(unsigned id) const
{
  if (id >= m_vocab.size()) {
    return NULL;
  }
  return m_vocab[ id ];
}

void Model1Vocabulary::Load(const std::string& fileName)
{
  InputFileStream inFile(fileName);
  FactorCollection &factorCollection = FactorCollection::Instance();
  std::string line;

  unsigned i = 0;
  if ( getline(inFile, line) ) { // first line of MGIZA vocabulary files seems to be special : "1       UNK     0"  -- skip if it's this
    ++i;
    std::vector<std::string> tokens = Tokenize(line);
    UTIL_THROW_IF2(tokens.size()!=3, "Line " << i << " in " << fileName << " has wrong number of tokens.");
    unsigned id = atoll( tokens[0].c_str() );
    if (! ( (id == 1) && (tokens[1] == "UNK") )) {
      const Factor* factor = factorCollection.AddFactor(tokens[1],false); // TODO: can we assume that the vocabulary is know and filter the model on loading?
      bool stored = Store(factor, id);
      UTIL_THROW_IF2(!stored, "Line " << i << " in " << fileName << " overwrites existing vocabulary entry.");
    }
  }
  while ( getline(inFile, line) ) {
    ++i;
    std::vector<std::string> tokens = Tokenize(line);
    UTIL_THROW_IF2(tokens.size()!=3, "Line " << i << " in " << fileName << " has wrong number of tokens.");
    unsigned id = atoll( tokens[0].c_str() );
    const Factor* factor = factorCollection.AddFactor(tokens[1],false); // TODO: can we assume that the vocabulary is know and filter the model on loading?
    bool stored = Store(factor, id);
    UTIL_THROW_IF2(!stored, "Line " << i << " in " << fileName << " overwrites existing vocabulary entry.");
  }
  inFile.Close();
}

void Model1LexicalTable::Load(const std::string &fileName, const Model1Vocabulary& vcbS, const Model1Vocabulary& vcbT)
{
  InputFileStream inFile(fileName);
  std::string line;

  unsigned i = 0;
  while ( getline(inFile, line) ) {
    ++i;
    std::vector<std::string> tokens = Tokenize(line);
    UTIL_THROW_IF2(tokens.size()!=3, "Line " << i << " in " << fileName << " has wrong number of tokens.");
    unsigned idS = atoll( tokens[0].c_str() );
    unsigned idT = atoll( tokens[1].c_str() );
    const Factor* wordS = vcbS.GetWord(idS);
    const Factor* wordT = vcbT.GetWord(idT);
    float prob = std::atof( tokens[2].c_str() );
    if ( (wordS != NULL) && (wordT != NULL) ) {
      m_ltable[ wordS ][ wordT ] = prob;
    }
    UTIL_THROW_IF2((wordS == NULL) || (wordT == NULL), "Line " << i << " in " << fileName << " has unknown vocabulary."); // TODO: can we assume that the vocabulary is know and filter the model on loading? Then remove this line.
  }
  inFile.Close();
}

// p( wordT | wordS )
float Model1LexicalTable::GetProbability(const Factor* wordS, const Factor* wordT) const
{
  float prob = m_floor;

  boost::unordered_map< const Factor*, boost::unordered_map< const Factor*, float > >::const_iterator iter1 = m_ltable.find( wordS );

  if ( iter1 != m_ltable.end() ) {
    boost::unordered_map< const Factor*, float >::const_iterator iter2 = iter1->second.find( wordT );
    if ( iter2 != iter1->second.end() ) {
      prob = iter2->second;
      if ( prob < m_floor ) {
        prob = m_floor;
      }
    }
  }
  return prob;
}

Model1Feature::Model1Feature(const std::string &line)
  : StatelessFeatureFunction(1, line)
  , m_is_syntax(false)
{
  VERBOSE(1, "Initializing feature " << GetScoreProducerDescription() << " ...");
  ReadParameters();
  VERBOSE(1, " Done.");
}

void Model1Feature::SetParameter(const std::string& key, const std::string& value)
{
  if (key == "path") {
    m_fileNameModel1 = value;
  } else if (key == "source-vocabulary") {
    m_fileNameVcbS = value;
  } else if (key == "target-vocabulary") {
    m_fileNameVcbT = value;
  } else {
    StatelessFeatureFunction::SetParameter(key, value);
  }
}

void Model1Feature::Load(AllOptions::ptr const& opts)
{
  m_options = opts;
  m_is_syntax = is_syntax(opts->search.algo);

  FEATUREVERBOSE(2, GetScoreProducerDescription() << ": Loading source vocabulary from file " << m_fileNameVcbS << " ...");
  Model1Vocabulary vcbS;
  vcbS.Load(m_fileNameVcbS);
  FEATUREVERBOSE2(2, " Done." << std::endl);
  FEATUREVERBOSE(2, GetScoreProducerDescription() << ": Loading target vocabulary from file " << m_fileNameVcbT << " ...");
  Model1Vocabulary vcbT;
  vcbT.Load(m_fileNameVcbT);
  FEATUREVERBOSE2(2, " Done." << std::endl);
  FEATUREVERBOSE(2, GetScoreProducerDescription() << ": Loading model 1 lexical translation table from file " << m_fileNameModel1 << " ...");
  m_model1.Load(m_fileNameModel1,vcbS,vcbT);
  FEATUREVERBOSE2(2, " Done." << std::endl);
  FactorCollection &factorCollection = FactorCollection::Instance();
  m_emptyWord = factorCollection.GetFactor(Model1Vocabulary::GIZANULL,false);
  UTIL_THROW_IF2(m_emptyWord==NULL, GetScoreProducerDescription()
                 << ": Factor for GIZA empty word does not exist.");

  const std::string punctuation = ",;.:!?";
  for (size_t i=0; i<punctuation.size(); ++i) {
    const std::string punct = punctuation.substr(i,1);
    FactorCollection &factorCollection = FactorCollection::Instance();
    const Factor* punctFactor = factorCollection.AddFactor(punct,false);
    std::pair<std::set<const Factor*>::iterator,bool> inserted = m_punctuation.insert(punctFactor);
  }
}

void Model1Feature::EvaluateWithSourceContext(const InputType &input
    , const InputPath &inputPath
    , const TargetPhrase &targetPhrase
    , const StackVec *stackVec
    , ScoreComponentCollection &scoreBreakdown
    , ScoreComponentCollection *estimatedScores) const
{
  const Sentence& sentence = static_cast<const Sentence&>(input);
  float score = 0.0;
  float norm = TransformScore(1+sentence.GetSize());

  for (size_t posT=0; posT<targetPhrase.GetSize(); ++posT) {
    const Word &wordT = targetPhrase.GetWord(posT);
    std::set<const Factor*>::const_iterator foundPunctuation = m_punctuation.find(wordT[0]);
    if (foundPunctuation != m_punctuation.end()) {
      continue;
    }
    if ( !wordT.IsNonTerminal() ) {
      float thisWordProb = m_model1.GetProbability(m_emptyWord,wordT[0]); // probability conditioned on empty word

      // cache lookup
      bool foundInCache = false;
      {
#ifdef WITH_THREADS
        boost::shared_lock<boost::shared_mutex> read_lock(m_accessLock);
#endif
        boost::unordered_map<const InputType*, boost::unordered_map<const Factor*, float> >::const_iterator sentenceCache = m_cache.find(&input);
        if (sentenceCache != m_cache.end()) {
          boost::unordered_map<const Factor*, float>::const_iterator cacheHit = sentenceCache->second.find(wordT[0]);
          if (cacheHit != sentenceCache->second.end()) {
            foundInCache = true;
            score += cacheHit->second;
            FEATUREVERBOSE(3, "Cached score( " << wordT << " ) = " << cacheHit->second << std::endl);
          }
        }
      }

      if (!foundInCache) {
        for (size_t posS=(m_is_syntax?1:0); posS<(m_is_syntax?sentence.GetSize()-1:sentence.GetSize()); ++posS) { // ignore <s> and </s>
          const Word &wordS = sentence.GetWord(posS);
          float modelProb = m_model1.GetProbability(wordS[0],wordT[0]);
          FEATUREVERBOSE(4, "p( " << wordT << " | " << wordS << " ) = " << modelProb << std::endl);
          thisWordProb += modelProb;
        }
        float thisWordScore = TransformScore(thisWordProb) - norm;
        FEATUREVERBOSE(3, "score( " << wordT << " ) = " << thisWordScore << std::endl);
        {
#ifdef WITH_THREADS
          // need to update cache; write lock
          boost::unique_lock<boost::shared_mutex> lock(m_accessLock);
#endif
          m_cache[&input][wordT[0]] = thisWordScore;
        }
        score += thisWordScore;
      }
    }
  }

  scoreBreakdown.PlusEquals(this, score);
}

void Model1Feature::CleanUpAfterSentenceProcessing(const InputType& source)
{
#ifdef WITH_THREADS
  // need to update cache; write lock
  boost::unique_lock<boost::shared_mutex> lock(m_accessLock);
#endif
  // clear cache
  boost::unordered_map<const InputType*, boost::unordered_map<const Factor*, float> >::iterator sentenceCache = m_cache.find(&source);
  if (sentenceCache != m_cache.end()) {
    sentenceCache->second.clear();
    m_cache.erase(sentenceCache);
  }
}

}

<|endoftext|>