void constrain_to_field(Node& n1) {

        // keep snake in the middle of the left area
        if (n1.type() == COMMIT || n1.display_type() == SNAKE_TAIL || n1.display_type() == HEAD) {
            n1.velocity().x -= 0.0001*pow(n1.pos().x-graph.left_border/2,3);
        }

        // keep HEAD around y = graph.history_pos
        if (n1.oid() == NodeID(REF, "HEAD"))
            n1.velocity().y -= 0.0001*pow(n1.pos().y-graph.history_pos,3);

        float border = 200;
        float strength = 0.00002;

        // keep blobs and trees in the middle area
        if (n1.type() == BLOB || n1.type() == TREE) {
            if (n1.pos().x < graph.left_border + border)
                n1.velocity().x += strength*pow(graph.left_border + border - n1.pos().x,3);
            if (n1.pos().x > graph.right_border - border)
                n1.velocity().x += strength*pow(graph.right_border - border - n1.pos().x,3);
            if (n1.pos().y < border)
                n1.velocity().y += strength*pow(border - n1.pos().y,3);
            if (n1.pos().y > graph.height-border)
                n1.velocity().y += strength*pow(graph.height - border - n1.pos().y,3);
        }
    }
Example #2
0
void GamesNode::updateChildren()
{
    util::DeletePtrContainer(&children_);

    Node *game = new Node(this);
    game->mutable_type() = NODE_TYPE_GAME_SUDOKU;
    game->mutable_name() = nodeName(game->type());
    game->mutable_display_name() = nodeDisplayName(game->type());
    children_.push_back(game);
}
Example #3
0
void If::doSemanticCheck()
{
    Node* condition = children_[0];
    Node* thenClause = children_[1];
    Node* elseClause = children_[2];
    
    // The resulting type is Void
    type_ = Void::get(context_->evalMode());

    // Semantic check the condition
    condition->semanticCheck();

    // Check that the type of the condition is 'Testable'
    if ( !isTestable(condition) )
        REP_ERROR(condition->location(), "The condition of the if is not Testable");

    // Dereference the condition as much as possible
    while ( condition->type() && condition->type()->noReferences() > 0 )
    {
        condition = mkMemLoad(condition->location(), condition);
        condition->setContext(childrenContext());
        condition->semanticCheck();
    }
    children_[0] = condition;
    // TODO (if): Remove this dereference from here

    if ( nodeEvalMode(this) == modeCt )
    {
        if ( !isCt(condition) )
            REP_ERROR(condition->location(), "The condition of the ct if should be available at compile-time (%1%)") % condition->type();

        // Get the CT value from the condition, and select an active branch
        Node* c = theCompiler().ctEval(condition);
        Node* selectedBranch = getBoolCtValue(c) ? thenClause : elseClause;

        // Expand only the selected branch
        if ( selectedBranch )
            setExplanation(selectedBranch);
        else
            setExplanation(mkNop(location_));
        return;
    }

    // Semantic check the clauses
    if ( thenClause )
        thenClause->semanticCheck();
    if ( elseClause )
        elseClause->semanticCheck();
}
Example #4
0
 void push_front(const Node& n)
 {
     children.insert(children.begin(), n);
     has_children = true;
     switch (n.type())
     {
     case Node::comment:
     case Node::css_import:
     case Node::rule:
     case Node::propset:
         has_statements = true;
         break;
     case Node::ruleset:
         has_blocks     = true;
         break;
     case Node::expansion:
         has_expansions = true;
         break;
     case Node::backref:
         has_backref    = true;
         break;
     default:
         break;
     }
     if (n.has_backref()) has_backref = true;
 }
Example #5
0
    void push_back(const Node& n)
    {
        children.push_back(n);
        has_children = true;
        switch (n.type())
        {
        case Node::comment:
        case Node::css_import:
        case Node::rule:
        case Node::propset:
            has_statements = true;
            break;

        case Node::ruleset:
            has_blocks     = true;
            break;

        case Node::if_directive:
        case Node::for_through_directive:
        case Node::for_to_directive:
        case Node::each_directive:
        case Node::while_directive:
        case Node::expansion:
            has_expansions = true;
            break;

        case Node::backref:
            has_backref    = true;
            break;

        default:
            break;
        }
        if (n.has_backref()) has_backref = true;
    }
Example #6
0
static void
sp_repr_save_writer(Document *doc, Inkscape::IO::Writer *out,
                    gchar const *default_ns,
                    gchar const *old_href_abs_base,
                    gchar const *new_href_abs_base)
{
    Inkscape::Preferences *prefs = Inkscape::Preferences::get();
    bool inlineattrs = prefs->getBool("/options/svgoutput/inlineattrs");
    int indent = prefs->getInt("/options/svgoutput/indent", 2);

    /* fixme: do this The Right Way */
    out->writeString( "<?xml version=\"1.0\" encoding=\"UTF-8\" standalone=\"no\"?>\n" );

    const gchar *str = static_cast<Node *>(doc)->attribute("doctype");
    if (str) {
        out->writeString( str );
    }

    for (Node *repr = sp_repr_document_first_child(doc);
         repr; repr = sp_repr_next(repr))
    {
        Inkscape::XML::NodeType const node_type = repr->type();
        if ( node_type == Inkscape::XML::ELEMENT_NODE ) {
            sp_repr_write_stream_root_element(repr, *out, TRUE, default_ns, inlineattrs, indent,
                                              old_href_abs_base, new_href_abs_base);
        } else {
            sp_repr_write_stream(repr, *out, 0, TRUE, GQuark(0), inlineattrs, indent,
                                 old_href_abs_base, new_href_abs_base);
            if ( node_type == Inkscape::XML::COMMENT_NODE ) {
                out->writeChar('\n');
            }
        }
    }
}
Example #7
0
void  GGASolver::setNodeCoeffs()
{
    for (int i = 0; i < nodeCount; i++)
    {
        // ... if node's head not fixed

        Node* node = network->node(i);
        if ( !node->fixedGrade )
        {
            // ... for dynamic tanks, add area terms to row i
            //     of the head solution matrix & r.h.s. vector

            if ( node->type() == Node::TANK && theta != 0.0 )
            {
                Tank* tank = static_cast<Tank*>(node);
                double a = tank->area / (theta * tstep);
                matrixSolver->addToDiag(i, a);

                a = a * tank->pastHead + (1.0 - theta) * tank->pastOutflow / theta;
                matrixSolver->addToRhs(i, a);
            }

            // ... for junctions, add effect of external outflows

            else if ( node->type() == Node::JUNCTION )
            {
                // ... update junction's net inflow
                xQ[i] -= node->outflow;
                matrixSolver->addToDiag(i, node->qGrad);
                matrixSolver->addToRhs(i, node->qGrad * node->head);
            }

            // ... add node's net inflow to r.h.s. row
            matrixSolver->addToRhs(i, (double)xQ[i]);
        }

        // ... if node has fixed head, force solution to produce it

        else
        {
            matrixSolver->setDiag(i, 1.0);
            matrixSolver->setRhs(i, node->head);
        }
    }
}
Example #8
0
ClosureCloser::NodeSet ClosureCloser::closureBody(Node& closure)
{
	// Add all the nodes causally after the closure outputs (skipping the first)
	assert(closure.type() == Node::Closure);
	NodeSet result;
	for(uint i = 1; i < closure.outArity(); ++i)
		closureBody(closure.out(i), result);
	return result;
}
Example #9
0
void ClosureCloser::annotateClosure(Node& closureNode)
{
	assert(closureNode.type() == Node::Closure);
	if(closureNode.has<ClosureProperty>())
		return;
	
	// Calculate the body of the closure
	NodeSet body = closureBody(closureNode);
	
	// Calculate the set of OutPorts linked from the body nodes, but not
	// in the body node set.
	OutPortSet border;
	for(auto node: body) {
		assert(node != nullptr);
		for(uint i = 0; i < node->inArity(); ++i) {
			InPort& in = node->in(i);
			if(in.source() == nullptr)
				continue;
			std::shared_ptr<OutPort> out = in.source();
			if(out == nullptr)
				continue;
			if(contains(body, out->parent().shared_from_this()))
				continue;
			border.insert(out);
		}
	}
	
	// Add any OutPorts linked directly to the InPorts, but not in the body set.
	for(uint i = 0; i < closureNode.inArity(); ++i) {
		InPort& in = closureNode.in(i);
		if(in.source() == nullptr)
			continue;
		std::shared_ptr<OutPort> out = in.source();
		if(out == nullptr)
			continue;
		if(contains(body, out->parent().shared_from_this()))
			continue;
		border.insert(out);
	}
	
	// Note: there are more meaningful sets other than `body`:
	//
	// * `lazy`: The nodes that feed only into body, but are not in body. These
	//           nodes can be deferred for lazy evaluation, turning a *lazy*
	//           closure context into a non-lazy one.
	// * `dead`: Nodes part of body, but who's output is does not end up in the
	//           input of the closure. These can be eliminated without
	//           consequences.
	
	// Apply arbitrary ordering
	ClosureProperty::ClosureSet vec;
	for(auto out: border)
		vec.push_back(out);
	
	// Set the closure property
	closureNode.set(ClosureProperty{vec});
}
Example #10
0
void FunRef::doSemanticCheck()
{
    ASSERT(children_.size() == 1);
    Node* resType = children_[0];
    resType->computeType();

    funDecl()->computeType();
    type_ = adjustMode(resType->type(), context_, location_);
}
Example #11
0
File: llvm.cpp Project: aptakhin/jt
void Assembly::next(Node node, String& out) {
	switch (node.type()) {
	case NodeType::FLOW: {
		auto flow = node.impl<FlowImpl>();
		for (auto& i: flow->flow()) {
			String tmp;
			next(i, tmp);
		}
	}
	break;

	case NodeType::VAR: {
		auto v = node.impl<VarImpl>();
		out = var(v->name());
		
		if (v->term().is<IntTermImpl>()) {
			*this << 
			out + " = shl i32 " + std::to_string(v->term().as<IntTermImpl>()->number()) + ", 0";
		}
		else if (v->value().is<FuncCallImpl>()) {
			next(v->value(), out);
		}
		else {
			*this << 
			out + " = shl i32 0, 0; Unknown type";
		}
	}
	break;

	case NodeType::FUNC_CALL: {
		auto call = node.impl<FuncCallImpl>();
		auto name = call->name();

		if (name == "op_plus") {
			auto lhs = tmp(), rhs = tmp();
			next(call->flow()->flow()[0], lhs);
			next(call->flow()->flow()[1], rhs);
			*this << 
			out + " = add i32 " + lhs + ", " + rhs;
		}
		else 
		if (name == "print") {
			auto out = tmp();
			next(call->flow()->flow()[0], out);
			*this << 
			tmp() + " = call i32 @print_i(i32 " + out + ")";
		}
		else 
		if (name == "op_get") {
			auto name = call->flow()->flow()[0];
			auto name_val = name->term().as<StringTermImpl>();
			out = var(name_val->str());
		}
	}
	}
}
Example #12
0
void ParserTest::boldItalic_embedded6()
{
  Buffer buffer("''italic'''''bold'''");
  Node *result = BoldItalicParser::parse(buffer);
  QVERIFY(result);
  QCOMPARE(buffer.pos(), 10);
  QCOMPARE(result->type(), Node::Italics);
  QCOMPARE(result->toText(), QString("italic"));
  delete result;
}
Example #13
0
  bool Node::operator==(Node rhs) const
  {
    Type t = type();
    if (t != rhs.type()) return false;

    switch (t)
    {
      case comma_list:
      case space_list:
      case expression:
      case term:
      case numeric_color: {
        if (size() != rhs.size()) return false;
        for (size_t i = 0, L = size(); i < L; ++i) {
          if (at(i) == rhs[i]) continue;
          else return false;
        }
        return true;
      } break;
      
      case variable:
      case identifier:
      case uri:
      case textual_percentage:
      case textual_dimension:
      case textual_number:
      case textual_hex:
      case string_constant: {
        return token().unquote() == rhs.token().unquote();
      } break;
      
      case number:
      case numeric_percentage: {
        return numeric_value() == rhs.numeric_value();
      } break;
      
      case numeric_dimension: {
        if (unit() == rhs.unit()) {
          return numeric_value() == rhs.numeric_value();
        }
        else {
          return false;
        }
      } break;
      
      case boolean: {
        return boolean_value() == rhs.boolean_value();
      } break;
      
      default: {
        return true;
      } break;
    }
    return false;
  }
void NodeParser::parseNodeData(string& id, Network* nw, vector<string>& tokens)
{
    Node* node = nw->node(id);
    if (node == nullptr) throw InputError(InputError::UNDEFINED_OBJECT, id);
    switch (node->type())
    {
    case Node::JUNCTION:  parseJuncData(static_cast<Junction*>(node), nw, tokens);  break;
    case Node::RESERVOIR: parseResvData(static_cast<Reservoir*>(node), nw, tokens); break;
    case Node::TANK:      parseTankData(static_cast<Tank*>(node), nw, tokens);      break;
    default:              throw InputError(InputError::UNDEFINED_OBJECT, id);
    }
}
Example #15
0
void ParserTest::boldItalic_embedded5()
{
  Buffer buffer("'''''abc''''' not parsed");
  Node *result = BoldItalicParser::parse(buffer);
  QVERIFY(result);
  QCOMPARE(buffer.pos(), 13);
  QCOMPARE(result->type(), Node::Italics);
  QCOMPARE(result->count(), 1);
  QCOMPARE(result->child(0)->type(), Node::Bold);
  QCOMPARE(result->child(0)->toText(), QString("abc"));
  delete result;
}
Example #16
0
TEST_F(DocumentParseTest, comment)
{
  Node *node;

  doc = Document::parse("<a><!--alert--></a>", &error);
  CHECK_PARSE_ERROR(error);

  auto top_element = get_top_element();

  node = top_element->first_child();
  ASSERT_EQ(NODE_TYPE_COMMENT, node->type());
}
Example #17
0
  bool nodesEqual(const Node& lhs, const Node& rhs, bool simpleSelectorOrderDependent) {
    if (lhs.type() != rhs.type()) {
      return false;
    }

    if (lhs.isCombinator()) {

    	return lhs.combinator() == rhs.combinator();

    } else if (lhs.isNil()) {

      return true; // no state to check

    } else if (lhs.isSelector()){

      return selectors_equal(*lhs.selector(), *rhs.selector(), simpleSelectorOrderDependent);

    } else if (lhs.isCollection()) {

      if (lhs.collection()->size() != rhs.collection()->size()) {
        return false;
      }

      for (NodeDeque::iterator lhsIter = lhs.collection()->begin(), lhsIterEnd = lhs.collection()->end(),
           rhsIter = rhs.collection()->begin(); lhsIter != lhsIterEnd; lhsIter++, rhsIter++) {

        if (!nodesEqual(*lhsIter, *rhsIter, simpleSelectorOrderDependent)) {
          return false;
        }

      }

      return true;

    }

    // We shouldn't get here.
    throw "Comparing unknown node types. A new type was probably added and this method wasn't implemented for it.";
  }
Example #18
0
void ParserTest::boldItalic_embedded1()
{
  Buffer buffer("'''abc''d'''''");
  Node *result = BoldItalicParser::parse(buffer);
  QVERIFY(result);
  QCOMPARE(result->type(), Node::Bold);
  QCOMPARE(result->count(), 2);
  QCOMPARE(result->child(0)->type(), Node::TextToken);
  QCOMPARE(result->child(0)->toText(), QString("abc"));
  QCOMPARE(result->child(1)->type(), Node::Italics);
  QCOMPARE(result->child(1)->toText(), QString("d"));
  delete result;
}
Example #19
0
int Node::createList() {
  if (_nodes != NULL) {
    errno = EBUSY;
    return -1;
  }
  // Create list
  struct dirent** direntList;
  int size = scandir(_path, &direntList, direntFilter, direntCompare);
  if (size < 0) {
    return -1;
  }
  // Cleanup list
  int size2 = size;
  while (size2--) {
    free(direntList[size2]);
  }
  free(direntList);
  // Bug in CIFS client, usually gets detected by two subsequent dir reads
  size2 = scandir(_path, &direntList, direntFilter, direntCompare);
  if (size != size2) {
    errno = EAGAIN;
    size = size2;
    size2 = -1;
  }
  if (size2 < 0) {
    while (size--) {
      free(direntList[size]);
    }
    free(direntList);
    return -1;
  }
  // Ok, let's parse
  _nodes = new list<Node*>;
  bool failed = false;
  char path[PATH_MAX];
  strcpy(path, _path);
  size_t path_len = strlen(path);
  path[path_len++] = '/';
  while (size--) {
    strcpy(&path[path_len], direntList[size]->d_name);
    Node *g = new Node(path);
    free(direntList[size]);
    if (g->type() == '?') {
      failed = true;
    }
    _nodes->push_front(g);
  }
  free(direntList);
  return failed ? -1 : 0;
}
Example #20
0
// Remove image nodes:
QList<Node *> Node::removeImageNodes()
{
    QList<Node *> out;
    for (int i=0; i<mChilds.size(); i++)
    {
        Node *child = mChilds[i];
        if (!child || (child->type() != Node::IMAGE))
            continue;
        out << child;
    }
    for (int i=0; i<out.size(); i++)
        mChilds.removeAll(out[i]);
    return out;
}
Example #21
0
bool CvsParser::ignore(const Node& node) {
    // No need to check more
    if (_mode == parser_modifiedandothers) {
        return false;
    }

    // Do not ignore control directory
    if (! strcmp(node.name(), _control_dir) && (node.type() == 'd')) {
        return false;
    }

    // Look for match in list
    bool controlled = false;
    for (_i = _files.begin(); _i != _files.end(); _i++) {
        if (! strcmp(_i->name(), node.name()) && (_i->type() == node.type())) {
            controlled = true;
            break;
        }
    }

    // Deal with result
    switch (_mode) {
    // We don't know whether controlled files are modified or not
    case parser_controlled:
    case parser_modified:
        if (controlled) return false;
        else return true;
    case parser_modifiedandothers:
        return false;
    case parser_others:
        if (controlled) return true;
        else return false;
    default:  // parser_disabled
        return false;
    }
}
Example #22
0
/*!
  Same as the other findNode(), but if the node with the
  specified \a name is not of the specified \a type, return
  0.
 */
Node *InnerNode::findNode(const QString& name, Type type)
{
    if (type == Function) {
        return primaryFunctionMap.value(name);
    }
    else {
        Node *node = childMap.value(name);
        if (node && node->type() == type) {
            return node;
        }
        else {
            return 0;
        }
    }
}
Example #23
0
void FlightStatuses::createMapping(Node *root)
{
    m_mappingEnglish.clear();
    m_mappingNorwegian.clear();
    QStack<Node*> pending;
    pending.push(root);
    while (!pending.isEmpty()) {
        Node *node = pending.pop();
        if (node->type() == "flightStatus") {
            const QString code = node->attribute("code");
            m_mappingEnglish.insert(code, node->attribute("statusTextEn"));
            m_mappingNorwegian.insert(code, node->attribute("statusTextNo"));
        }
        for (int i = 0; i < node->childCount(); ++i)
            pending.push(node->child(i));
    }
}
Example #24
0
  // Remove duplicate selectors from a selector group. Used when extending.
  Node remove_duplicate_selectors(Node group, Node_Factory& new_Node)
  {
    if (group.type() != Node::selector_group) return group;

    Node filtered(new_Node(Node::selector_group, group.path(), group.line(), 1));
    for (size_t i = 0, S = group.size(); i < S; ++i) {
      bool found_dup = false;
      for (size_t j = 0; j < filtered.size(); ++j) {
        if (group[i] == filtered[j]) {
          found_dup = true;
          break;
        }
      }
      if (!found_dup) filtered << group[i];
    }

    return filtered;
  }
Example #25
0
void
Downloader::downloadNode (Node& node, const boost::filesystem::path& path)
{
    TransferProgress saved{};
    {
        std::lock_guard<std::mutex> l{_mut};
        saved = _progress;
    }

    try
    {
        doDownloadNode(node, path);
    }
    catch (const std::exception&)
    {
        if (_downloading != nullptr && _downloading->state() == FileTransferer::State::canceled)
        {
            // Ignore cancel errors
            // TODO: this should be reported.
            std::lock_guard<std::mutex> l{_mut};
            _downloading = nullptr;
            return;
        }

        auto error = utils::exceptionInfos();
        GIGA_DEBUG_LOG(debug, error);
        try
        {
            saved.fileDone += node.type() == Node::Type::file ? 1 : node.nbFiles();
            saved.bytesTransfered += node.size();

            std::lock_guard<std::mutex> l{_mut};
            _progress = saved;
            _onErrorFct(node.id(), node.name(), std::move(error));
            _downloading = nullptr;
        }
        catch (...)
        {
            GIGA_DEBUG_LOG(warning, utils::exceptionInfos());
        }
    }
}
Example #26
0
  Node normalize_selector(Node s, Node_Factory& new_Node)
  {
    switch (s.type())
    {
      case Node::selector_group: {
        Node normalized(new_Node(Node::selector_group, s.path(), s.line(), 1));
        set<Node> normalizer;
        for (size_t i = 0, S = s.size(); i < S; ++i)
          normalizer.insert(normalize_selector(s[i], new_Node));
        for (set<Node>::iterator i = normalizer.begin(); i != normalizer.end(); ++i)
          normalized << *i;
        return normalized;
      } break;

      case Node::selector: {
        Node normalized(new_Node(Node::selector, s.path(), s.line(), s.size()));
        for (size_t i = 0, S = s.size(); i < S; ++i)
          normalized << normalize_selector(s[i], new_Node);
        return normalized;
      } break;

      case Node::simple_selector_sequence: {
        Node normalized(new_Node(Node::simple_selector_sequence, s.path(), s.line(), 1));
        set<Node> normalizer;
        size_t i = 0;
        if (!selector_is_qualifier(s[0])) {
          normalized << s[0];
          i = 1;
        }
        for (size_t S = s.size(); i < S; ++i)
          normalizer.insert(normalize_selector(s[i], new_Node));
        for (set<Node>::iterator i = normalizer.begin(); i != normalizer.end(); ++i)
          normalized << *i;
        return normalized;
      } break;

      default: {
        return s;
      } break;
    }
    return s;
  }
Example #27
0
Qt::ItemFlags ObjectSet::flags(const QModelIndex &index) const
{
    if (!index.isValid())
        return 0;

    Qt::ItemFlags flags = QAbstractItemModel::flags(index) & ~Qt::ItemIsSelectable;

    Node *node = static_cast<Node *>(index.internalPointer());

    switch (node->type())
    {
    case NT_FILE:
        return flags | Qt::ItemIsUserCheckable;
    case NT_PATCH:
        return flags | Qt::ItemIsUserCheckable;
    case NT_COMPONENTS:
        return flags & ~Qt::ItemIsSelectable;
    case NT_COMPONENT:
        return flags | Qt::ItemIsUserCheckable | Qt::ItemNeverHasChildren;
    }
}
Example #28
0
  bool selector_is_qualifier(Node s)
  {
    switch (s.type())
    {
      case Node::pseudo:
      case Node::pseudo_negation:
      case Node::functional_pseudo:
      case Node::attribute_selector: {
        return true;
      } break;

      case Node::simple_selector: {
        if ((*s.token().begin == '.') || (*s.token().begin == '#')) return true;
      } break;

      default: {
        return false;
      } break;
    }
    return false;
  }
Example #29
0
  bool Node::operator==(const Node& rhs) const {
    if (this->type() != rhs.type()) {
      return false;
    }

    if (this->isCombinator()) {

      return this->combinator() == rhs.combinator();

    } else if (this->isNil()) {

      return true; // no state to check

    } else if (this->isSelector()){

      return *this->selector() == *rhs.selector();

    } else if (this->isCollection()) {

      if (this->collection()->size() != rhs.collection()->size()) {
        return false;
      }

      for (NodeDeque::iterator lhsIter = this->collection()->begin(), lhsIterEnd = this->collection()->end(),
           rhsIter = rhs.collection()->begin(); lhsIter != lhsIterEnd; lhsIter++, rhsIter++) {

        if (*lhsIter != *rhsIter) {
          return false;
        }

      }

      return true;

    }

    // We shouldn't get here.
    throw "Comparing unknown node types. A new type was probably added and this method wasn't implemented for it.";
  }
    void turn(Node& n1, Node& n2) {
        float direction = 0;
        if (n1.display_type() == SNAKE || n1.display_type() == HEAD || n1.display_type() == SNAKE_TAIL) {
            if (n2.display_type() == SNAKE || n2.display_type() == SNAKE_TAIL)
                direction = M_PI;
            else
                direction = -M_PI*1/2;
        } else if (n1.display_type() == SIGN)
            direction = -M_PI*0.75;
        else if (n1.oid().type == INDEX_ENTRY)
            direction = M_PI*0.5;
        else if (n1.type() == TREE)
            direction = -M_PI*0.5;
        else
            return;

        float correction = small_angle(n1.dir_to(n2),direction);
        float strength = 50*correction;
        n1.velocity().x += strength*sin(n1.dir_to(n2)+M_PI/2);
        n1.velocity().y += strength*cos(n1.dir_to(n2)+M_PI/2);

        n2.velocity().x -= strength*sin(n1.dir_to(n2)+M_PI/2);
        n2.velocity().y -= strength*cos(n1.dir_to(n2)+M_PI/2);
    }