Пример #1
0
   double Face :: fieldIndex( double k ) const
   {
      if( isBoundary() ) return 0.;

      double Omega = 0.;
      double index = 0.;
      HalfEdgeCIter hi = he;
      do
      {
         double phiI = hi->vertex->directionField.arg();
         double phiJ = hi->flip->vertex->directionField.arg();
         double thetaI = hi->angularCoordinate;
         double thetaJ = hi->flip->angularCoordinate + M_PI;
         double dTheta = thetaI - thetaJ;

         Omega += dTheta;
         index += fmodPI( phiJ - phiI + k*dTheta );

         hi = hi->next;
      }
      while( hi != he );

      index -= k * fmodPI(Omega);

      return lround( index / (2.*M_PI) );
   }
Пример #2
0
BoundingBox Face::boundingBox() const
{
    if (isBoundary()) {
        return BoundingBox(he->vertex->position, he->next->vertex->position);
    }
    
    Eigen::Vector3d p1 = he->vertex->position;
    Eigen::Vector3d p2 = he->next->vertex->position;
    Eigen::Vector3d p3 = he->next->next->vertex->position;
    
    Eigen::Vector3d min = p1;
    Eigen::Vector3d max = p1;
    
    if (p2.x() < min.x()) min.x() = p2.x();
    if (p3.x() < min.x()) min.x() = p3.x();
    
    if (p2.y() < min.y()) min.y() = p2.y();
    if (p3.y() < min.y()) min.y() = p3.y();
    
    if (p2.z() < min.z()) min.z() = p2.z();
    if (p3.z() < min.z()) min.z() = p3.z();
    
    if (p2.x() > max.x()) max.x() = p2.x();
    if (p3.x() > max.x()) max.x() = p3.x();
    
    if (p2.y() > max.y()) max.y() = p2.y();
    if (p3.y() > max.y()) max.y() = p3.y();
    
    if (p2.z() > max.z()) max.z() = p2.z();
    if (p3.z() > max.z()) max.z() = p3.z();
    
    return BoundingBox(min, max);
}
Пример #3
0
double Face::area() const
{
    if (isBoundary()) {
        return 0.0;
    }
    
    return 0.5 * normal().norm();
}
Пример #4
0
//get Boundary Adjacent Vertexes of a vertex
void HalfEdgeMesh::getBoundaryAdjacentVertexes(int vertexIndex, vector<int>& adjVtx_ids){
	for(int i=0;i<HEHalfEdges.size();i++){
		HEHalfEdge he=HEHalfEdges.at(i);
		int vtx_id=he.origin;

		int next_edge_id=HEHalfEdges.at(i).next;
		HEHalfEdge next_he=HEHalfEdges.at(next_edge_id);
		int next_vtx_id=HEHalfEdges.at(next_edge_id).origin;

		if(vtx_id==vertexIndex&&isBoundary(he)){
			adjVtx_ids.push_back(next_vtx_id);
		}
		else if(next_vtx_id==vertexIndex&&isBoundary(he)){
			adjVtx_ids.push_back(vtx_id);
		}
	}
}
	bool isBoundary(const _Internal::_triangle* t)
	{
		for(int i=0; i<3; ++i)
		{
			if(isBoundary(t->edges[i])) 
				return true;
		}
		return false;
	}
//! returns the previous boundary from given index, including the index in the search.
//! If index is a boundary, it is returned and current is decreased by one,
//! otherwise works as previous()
int MIcuBreakIterator::previousInclusive(int index)
{
    Q_D(MIcuBreakIterator);
    if (isBoundary(index)) {
        d->current = index - 1;
        return index;
    } else {
        return previous(index);
    }
}
Пример #7
0
bool Lexer::isDoubleCharOperator (int c0, int c1, int c2)
{
  return (c0 == '=' && c1 == '=')                        ||
         (c0 == '!' && c1 == '=')                        ||
         (c0 == '<' && c1 == '=')                        ||
         (c0 == '>' && c1 == '=')                        ||
         (c0 == 'o' && c1 == 'r' && isBoundary (c1, c2)) ||
         (c0 == '|' && c1 == '|')                        ||
         (c0 == '&' && c1 == '&')                        ||
         (c0 == '!' && c1 == '~');
}
	/*
	An edge is deemed safe if removal of it will not make the shape irregular.
	A shape is irregular if a vertex has more than two edges that are on the boundary. 
	*/
	bool isSafe(const _Internal::_edge* e) 
	{
		if(isBoundary(e))
		{
			_Internal::_triangle* tr = e->faces[0] ? e->faces[0] : e->faces[1]; //one has to be non NULL
			if(tr == NULL) return false; //this is a dangling edge. not safe.

			_Internal::_vertex* v = findOpposite(tr, e);
			for(int j=0; j<v->edges.size(); ++j)
			{
				const _Internal::_edge* e2 = v->edges[j];
				if(isBoundary(e2))
				{
					return false;
				}
			}
			return true;
		}
		return false; 
	}
Пример #9
0
//if a Vertex is on boundary
bool HalfEdgeMesh::isOnBoundary(int vtx_index){
	for(int i=0;i<HEHalfEdges.size();i++){
		HEHalfEdge he=HEHalfEdges.at(i);

		if(he.origin==vtx_index&&isBoundary(he)){
			return true;
		}
	}

	return false;
}
//! returns the previous boundary including the current index in the search.
//! If current index is a boundary, it is returned and current is decreased by one,
//! otherwise works as previous()
int MIcuBreakIterator::previousInclusive()
{
    Q_D(MIcuBreakIterator);
    if (isBoundary()) {
        int result = d->current;
        --d->current;
        return result;

    } else {
        return previous();
    }
}
Пример #11
0
void Lanes::changeActiveLane(const CGitHash& sha) {

	int& t = typeVec[activeLane];
	if (t == INITIAL || isBoundary(t))
		t = EMPTY;
	else
		t = NOT_ACTIVE;

	int idx = findNextSha(sha, 0); // find first sha
	if (idx != -1)
		typeVec[idx] = ACTIVE; // called before setBoundary()
	else
		idx = add(BRANCH, sha, activeLane); // new branch

	activeLane = idx;
}
Пример #12
0
void Lexer::word() {
    _word[_wi++] = _stream->current();
    while (!isBoundary(_stream->peek()))
        _word[_wi++] = _stream->read();

    // does it look like a number?
    _word[_wi++] = '\0';

    if (isint(_word))
        add(new (collect) Term(TInt, atol(_word)));
    else if (isfloat(_word))
        add(new (collect) Term(TDouble, atof(_word)));
    else
        add(new (collect) Term(TSymbol, Sym::lookup(_word)));
    _wi = 0;
}
Пример #13
0
Eigen::Vector3d Face::centroid() const
{
    Eigen::Vector3d centroid;

    if (isBoundary()) {
        centroid = (he->vertex->position +
                    he->next->vertex->position) / 2.0;
        
    } else {
        centroid = (he->vertex->position +
                    he->next->vertex->position +
                    he->next->next->vertex->position) / 3.0;
    }

    return centroid;
}
Пример #14
0
   void Vertex::computeCentroid( void )
   {
      // TODO Compute the average position of all neighbors of this vertex, and
      // TODO store it in Vertex::centroid.  This value will be used for resampling.
			HalfedgeIter h = halfedge();
			centroid.x = 0; centroid.y = 0; centroid.z = 0;
			do
			{
				h = h->twin();
				Vector3D neighbor = h->vertex()->position;
				centroid += neighbor;
				h = h->next();
			}
			while(h != halfedge());
		 //By convention, Vertex::degree() returns the face degree,
		 //not the edge degree. The edge degree can be computed by finding the face
		 //degree, and adding 1 if the vertex is a boundary vertex.
		 int degree = this->degree();
		 if(isBoundary())
			 degree++;
			centroid /= (double)degree;
   }
Пример #15
0
//----------------------------------------------------------------------------
void PrNestedTriangulation::getParents(int i, int jlev, int& p1, int& p2)
//-----------------------------------------------------------------------------
// Assuming that node i belongs to V^j\V^{j-1} and that
// jlev >= 1, find i's two parent nodes in V^{j-1} p1 and p2.
{
  vector<int> neighbours;
  getNeighbours(i,jlev,neighbours);
  if(isBoundary(i))
  {
    // Then there are exactly four neighbours. We want the
    // first and last ones.
    p1 = neighbours[0];
    p2 = neighbours[3];
    return;
  }
  else
  {
    // Then there are exactly six neighbours. Find the first
    // coarse one.
    if(neighbours[0] < getNumNodes(jlev-1))
    {
      p1 = neighbours[0];
      p2 = neighbours[3];
      return;
    }
    else if(neighbours[1] < getNumNodes(jlev-1))
    {
      p1 = neighbours[1];
      p2 = neighbours[4];
      return;
    }
    else
    {
      p1 = neighbours[2];
      p2 = neighbours[5];
      return;
    }
  }
}
	Triangulator::Triangulator(const vector<CParticleF>& pnts)
	{
		for(int i=0; i<pnts.size(); ++i)
		{
			points.push_back(new _Internal::_vertex(pnts[i]));
		}

		vector<TriangulateBourke::Triplet> delaunayTriangles = TriangulateBourke::DelaunayTriangulation(pnts);
		/*if(tripletSanityCheck(delaunayTriangles, pnts.size()) > 0)
		{
			int i=0;
		}*/
		for(int i=0; i<delaunayTriangles.size(); i++)
		{
			int xk = delaunayTriangles[i].index[0];
			int yk = delaunayTriangles[i].index[1];
			int zk = delaunayTriangles[i].index[2];
			assert(xk>=0 && xk<pnts.size() && yk>=0 && yk<pnts.size() && zk>=0 && zk<pnts.size());
			CParticleF x = pnts[xk];
			CParticleF y = pnts[yk];
			CParticleF z = pnts[zk];

			float ccw = CounterClockWise(x, y, z);
			if(ccw > 0)
			{
				//arrange them in clockwise orientation
				swap(xk, zk);
				swap(x, z);
			}

			_Internal::_edge* tedges[3];
			tedges[0] = (new _Internal::_edge(points[xk], points[yk]));
			tedges[1] = (new _Internal::_edge(points[yk], points[zk]));
			tedges[2] = (new _Internal::_edge(points[zk], points[xk]));
			_Internal::_triangle* tr = new _Internal::_triangle(0, 0, 0, points[xk], points[yk], points[zk]);
			faces.push_back(tr);
			//add new edges to the edge vector. Make association with a new face and edges.
			for(int j=0; j<3; ++j)
			{
				vector<_Internal::_edge*>::iterator it = find_if(edges.begin(), edges.end(), _Internal::_edge_equal(tedges[j]));
				if(it == edges.end())
				{
					edges.push_back(tedges[j]);
				}
				else
				{
					delete tedges[j];
					tedges[j] = *it;
				}
				tr->edges[j] = tedges[j];
				tedges[j]->AddFace(tr);
			}
			points[xk]->AddEdge(tedges[0]);
			points[xk]->AddEdge(tedges[2]);
			points[yk]->AddEdge(tedges[0]);
			points[yk]->AddEdge(tedges[1]);
			points[zk]->AddEdge(tedges[1]);
			points[zk]->AddEdge(tedges[2]);
		}
		sort(edges.begin(), edges.end(), _Internal::_edge_less);
		//classify each edge. Initially, they are either Inside or Boundary.
		//After edge-removal, we can have Hole edges when an Inside edge is removed.
		for(int i=0; i<edges.size(); ++i)
		{
			if(isBoundary(edges[i]))
			{
				edges[i]->type = _Internal::Boundary;
			}
			else
			{
				edges[i]->type = _Internal::Inside;
			}
			Node<_Internal::_edge*>* node = makeset(edges[i]);
			vnodes.push_back(node);
			edges[i]->node = node;

		}
		//make a cluster of boundary edges. Initially, there is only one cluster
		Node<_Internal::_edge*>* root = NULL;
		for(int i=0; i<edges.size(); ++i)
		{
			if(edges[i]->type == _Internal::Boundary)
			{	
				if(root == NULL)
				{
					root = edges[i]->node;
				}
				else
				{
					merge(edges[i]->node, root);
				}
			}
		}
	}
Пример #17
0
//get two sets of sequential Adjacent Vertexes of two vertexes that is in a half edge which is not a boundary edge
void HalfEdgeMesh::getSequentialAdjacentVertexes(int he_id, vector<int>& adjVtx_ids0, vector<int>& adjVtx_ids1){

	if(!isBoundary(HEHalfEdges.at(he_id))){
		int twin_id=HEHalfEdges.at(he_id).twin;

		int tem_id=-1;
		int vtx0_id=HEHalfEdges.at(he_id).origin;
		int vtx1_id=HEHalfEdges.at(twin_id).origin;

		if(isOnBoundary(vtx0_id)){
			vector<int> vtx_ids;
			getBoundaryAdjacentVertexes(vtx0_id, vtx_ids);

			int tem_next=-1;
			int tem_pre=-1;

			for(int i=0;i<HEHalfEdges.size();i++){
				if(HEHalfEdges.at(i).origin==vtx0_id&&(HEHalfEdges.at(HEHalfEdges.at(i).next).origin==vtx_ids.at(0)||HEHalfEdges.at(HEHalfEdges.at(i).next).origin==vtx_ids.at(1))){
					tem_next=HEHalfEdges.at(i).next;
					tem_pre=HEHalfEdges.at(i).prev;
					adjVtx_ids0.push_back(HEHalfEdges.at(tem_next).origin);
					break;
				}
			}

			tem_id=HEHalfEdges.at(tem_pre).twin;
			while(tem_id!=-1){
				tem_next=HEHalfEdges.at(tem_id).next;
				tem_pre=HEHalfEdges.at(tem_id).prev;
				adjVtx_ids0.push_back(HEHalfEdges.at(tem_next).origin);

				tem_id=HEHalfEdges.at(tem_pre).twin;
			}

			adjVtx_ids0.push_back(HEHalfEdges.at(tem_pre).origin);

			vector<int> adjVtx_ids_tem;
			int index_tem=-1;

			for(int k=0;k<adjVtx_ids0.size();k++){
				if(adjVtx_ids0.at(k)==vtx1_id){
					index_tem=k;
				}
			}

			for(int k=index_tem;k<adjVtx_ids0.size();k++){
				adjVtx_ids_tem.push_back(adjVtx_ids0.at(k));
			}

			for(int k=0;k<index_tem;k++){
				adjVtx_ids_tem.push_back(adjVtx_ids0.at(k));
			}

			adjVtx_ids0=adjVtx_ids_tem;
		}
		else{

			adjVtx_ids0.push_back(HEHalfEdges.at(twin_id).origin);

			while(twin_id!=tem_id){
				if(tem_id==-1){
					tem_id=twin_id;
				}

				int next_id=HEHalfEdges.at(tem_id).next;
				tem_id=HEHalfEdges.at(next_id).twin;

				adjVtx_ids0.push_back(HEHalfEdges.at(tem_id).origin);
			}

			invert(adjVtx_ids0);
			adjVtx_ids0.pop_back();
		}

		tem_id=-1;

		if(isOnBoundary(vtx1_id)){

			vector<int> vtx_ids;
			getBoundaryAdjacentVertexes(vtx1_id, vtx_ids);

			int tem_next=-1;
			int tem_pre=-1;

			for(int i=0;i<HEHalfEdges.size();i++){
				if(HEHalfEdges.at(i).origin==vtx1_id&&(HEHalfEdges.at(HEHalfEdges.at(i).next).origin==vtx_ids.at(0)||HEHalfEdges.at(HEHalfEdges.at(i).next).origin==vtx_ids.at(1))){

					tem_next=HEHalfEdges.at(i).next;
					tem_pre=HEHalfEdges.at(i).prev;
					adjVtx_ids1.push_back(HEHalfEdges.at(tem_next).origin);

					break;
				}
			}

			tem_id=HEHalfEdges.at(tem_pre).twin;
			while(tem_id!=-1){
				tem_next=HEHalfEdges.at(tem_id).next;
				tem_pre=HEHalfEdges.at(tem_id).prev;
				adjVtx_ids1.push_back(HEHalfEdges.at(tem_next).origin);

				tem_id=HEHalfEdges.at(tem_pre).twin;
			}

			adjVtx_ids1.push_back(HEHalfEdges.at(tem_pre).origin);

			vector<int> adjVtx_ids_tem;
			int index_tem=-1;

			for(int k=0;k<adjVtx_ids1.size();k++){
				if(adjVtx_ids1.at(k)==vtx0_id){
					index_tem=k;
				}
			}

			for(int k=index_tem;k<adjVtx_ids1.size();k++){
				adjVtx_ids_tem.push_back(adjVtx_ids1.at(k));
			}

			for(int k=0;k<index_tem;k++){
				adjVtx_ids_tem.push_back(adjVtx_ids1.at(k));
			}

			adjVtx_ids1=adjVtx_ids_tem;
		}
		else{
			adjVtx_ids1.push_back(HEHalfEdges.at(he_id).origin);

			while(he_id!=tem_id){
				if(tem_id==-1){
					tem_id=he_id;
				}

				int next_id=HEHalfEdges.at(tem_id).next;
				tem_id=HEHalfEdges.at(next_id).twin;

				adjVtx_ids1.push_back(HEHalfEdges.at(tem_id).origin);
			}

			invert(adjVtx_ids1);
			adjVtx_ids1.pop_back();
		}
	}
}
Пример #18
0
IOBufQueue RFC1867Codec::readToBoundary(bool& foundBoundary) {
  IOBufQueue result{IOBufQueue::cacheChainLength()};
  BoundaryResult boundaryResult = BoundaryResult::NO;

  while (!input_.empty() && boundaryResult != BoundaryResult::PARTIAL) {
    const IOBuf* head = input_.front();
    uint64_t len = head->length();
    const uint8_t *ptr = head->data();

    /* iterate through first character matches */
    while (len > 0 && (ptr = (const uint8_t*)memchr(ptr, boundary_[0], len))) {
      /* calculate length after match */
      uint64_t readlen = (ptr - head->data());
      len = head->length() - readlen;
      boundaryResult =
        isBoundary(*head, readlen, boundary_.data(), boundary_.length());
      if (boundaryResult == BoundaryResult::YES) {
        CHECK(readlen < head->length());
        bool hasCr = false;
        if (readlen == 0 && pendingCR_) {
          pendingCR_.reset();
        }
        if (readlen > 0) {
          // If the last read char is a CR omit from result
          Cursor c(head);
          c.skip(readlen - 1);
          uint8_t ch = c.read<uint8_t>();
          if (ch == '\r') {
            --readlen;
            hasCr = true;
          }
        }
        result.append(std::move(pendingCR_));
        result.append(input_.split(readlen));
        uint32_t trimLen = boundary_.length() + (hasCr ? 1 : 0);
        input_.trimStart(trimLen);
        bytesProcessed_ += readlen + trimLen;
        foundBoundary = true;
        return result;
      } else if (boundaryResult == BoundaryResult::PARTIAL) {
        break;
      } else if (pendingCR_) {
        // not a match, append pending CR to result
        result.append(std::move(pendingCR_));
      }

      /* next character */
      ptr++; len--;
    }
    uint64_t resultLen = ptr ? ptr - head->data() : head->length();
    // Put pendingCR_ in result if there was no partial match in head, or a
    // partial match starting after the first character
    if ((boundaryResult == BoundaryResult::NO || resultLen > 0) &&
        pendingCR_) {
      result.append(std::move(pendingCR_));
    }
    // the boundary does not start through resultLen, append it
    // to result, except maybe the last char if it's a CR.
    if (resultLen > 0 && head->data()[resultLen - 1] == '\r') {
      result.append(input_.split(resultLen - 1));
      CHECK(!pendingCR_);
      pendingCR_ = input_.split(1);
    } else {
      result.append(input_.split(resultLen));
    }
    bytesProcessed_ += resultLen;
  }

  // reached the end but no boundary found
  foundBoundary = false;

  return result;
}
Пример #19
0
bool Lexer::isTripleCharOperator (int c0, int c1, int c2, int c3)
{
  return (c0 == 'a' && c1 == 'n' && c2 == 'd' && isBoundary (c2, c3)) ||
         (c0 == 'x' && c1 == 'o' && c2 == 'r' && isBoundary (c2, c3)) ||
         (c0 == '!' && c1 == '=' && c2 == '=');
}
Пример #20
0
std::unique_ptr<IOBuf> RFC1867Codec::onIngress(std::unique_ptr<IOBuf> data) {
  static auto dummyBuf = IOBuf::wrapBuffer(kDummyGet.data(),
                                           kDummyGet.length());
  IOBufQueue result{IOBufQueue::cacheChainLength()};
  bool foundBoundary = false;
  BoundaryResult br = BoundaryResult::NO;

  input_.append(std::move(data));
  while (!input_.empty()) {
    switch (state_) {
      case ParserState::START:
        // first time, must start with boundary without leading \n
        br = isBoundary(*input_.front(), 0, boundary_.data() + 1,
                        boundary_.length() - 1);
        if (br == BoundaryResult::NO) {
          if (callback_) {
            LOG(ERROR) << "Invalid starting sequence";
            callback_->onError();
          }
          state_ = ParserState::ERROR;
          return nullptr;
        } else if (br == BoundaryResult::PARTIAL) {
          return input_.move();
        }
        input_.trimStart(boundary_.length() - 1);
        bytesProcessed_ += boundary_.length() - 1;
        state_ = ParserState::HEADERS_START;
        // fall through

      case ParserState::HEADERS_START:
        {
          if (input_.chainLength() < 3) {
            return input_.move();
          }
          Cursor c(input_.front());
          char firstTwo[2];
          c.pull(firstTwo, 2);
          // We have at least 3 chars available to read
          uint8_t toTrim = 3;
          if (memcmp(firstTwo, "--", 2) == 0) {
            do {
              auto ch = c.read<char>();
              if (ch == '\n') {
                input_.trimStart(toTrim);
                state_ = ParserState::DONE;
              } else if (ch == '\r') {
                // Every \r we encounter is a char we must trim but we must
                // make sure we have sufficient data available in input_ to
                // keep reading (toTrim is always one pos ahead to handle the
                // expected \n)
                ++toTrim;
                if (input_.chainLength() < toTrim) {
                  return input_.move();
                }
              } else {
                state_ = ParserState::ERROR;
              }
            } while (state_ == ParserState::HEADERS_START);
            break;
          }
        }
        headerParser_.setParserPaused(false);
        headerParser_.onIngress(*dummyBuf);
        CHECK(!parseError_);
        state_ = ParserState::HEADERS;
        // fall through

      case ParserState::HEADERS:
        while (!parseError_ && input_.front() &&
               state_ == ParserState::HEADERS) {
          size_t bytesParsed = headerParser_.onIngress(*input_.front());
          input_.trimStart(bytesParsed);
          bytesProcessed_ += bytesParsed;
        }
        if (parseError_) {
          if (callback_) {
            LOG(ERROR) << "Error parsing header data: "
                       << IOBufPrinter::printHexFolly(input_.front());

            callback_->onError();
          }
          state_ = ParserState::ERROR;
          return nullptr;
        }
        break;

      case ParserState::PARAM_DATA:
        result = readToBoundary(foundBoundary);
        value_.append(result.move());
        if (foundBoundary) {
          if (callback_) {
            auto value = value_.move()->moveToFbString();
            callback_->onParam(param_, value.toStdString(), bytesProcessed_);
          }
          state_ = ParserState::HEADERS_START;
        } else {
          return input_.move();
        }
        break;

      case ParserState::FILE_DATA:
        result = readToBoundary(foundBoundary);
        value_.append(result.move());
        if (!value_.empty() && callback_) {
          if (callback_->onFileData(value_.move(), bytesProcessed_) < 0) {
            LOG(ERROR) << "Callback returned error";
            state_ = ParserState::ERROR;
            return nullptr;
          }
        }
        if (foundBoundary) {
          if (callback_) {
            callback_->onFileEnd(true, bytesProcessed_);
          }
          state_ = ParserState::HEADERS_START;
        } else {
          if (input_.chainLength() > 0) {
            VLOG(5) << "Trailing input="
                    << IOBufPrinter::printHexFolly(input_.front());
          }
          return input_.move();
        }
        break;
      case ParserState::DONE:
      case ParserState::ERROR:
        // abort, consume all input
        return nullptr;
    }
  }
  return nullptr;
}
Пример #21
0
   void MeshResampler::resample( HalfedgeMesh& mesh )
   {
      // TODO Compute the mean edge length.
			double mean2 = 0;
			for(auto edge = mesh.edgesBegin(); edge != mesh.edgesEnd(); ++edge)
			{
				Vector3D v0 = edge->halfedge()->vertex()->position;
				Vector3D v1 = edge->halfedge()->twin()->vertex()->position;
				mean2 += (v0 - v1).norm();
			}
			mean2 /= (double)mesh.nEdges();
			mean2 *= mean2;
		 
      // TODO Repeat the four main steps for 5 or 6 iterations
			const int ITER_TIMES = 5;
			const int SMOOTH_TIMES = 20;
			const double WEIGHT_FACTOR = 0.2;
			const double LONG_EDGE_2 = 1.7777777778;
			const double SHORT_EDGE_2 = 0.64;
			std::unordered_set<EdgeIter> edgeSet;
			edgeSet.reserve(mesh.nEdges());
			
			for(int i = 0; i < ITER_TIMES; ++i)
			{
				// TODO Split edges much longer than the target length (being careful about how the loop is written!)
				EdgeIter old_end = mesh.edgesEnd();
				--old_end;
				for(auto edge = mesh.edgesBegin(); edge != mesh.edgesEnd(); ++edge)
				{
					Vector3D v0 = edge->halfedge()->vertex()->position;
					Vector3D v1 = edge->halfedge()->twin()->vertex()->position;
					if((v0 - v1).norm2() > LONG_EDGE_2 * mean2)
					{
						mesh.splitEdge(edge);
					}
					if(edge == old_end)
						break;
				}
				
				// TODO Collapse edges much shorter than the target length.  Here we need to be EXTRA careful about
				// TODO advancing the loop, because many edges may have been destroyed by a collapse (which ones?)
				edgeSet.clear();
				for(auto edge = mesh.edgesBegin(); edge != mesh.edgesEnd(); ++edge)
				{
					edgeSet.insert(edge);
				}
				while(edgeSet.size() > 0)
				{
					EdgeIter curr = *(edgeSet.begin());
					edgeSet.erase(edgeSet.begin());
					
					VertexIter v0 = curr->halfedge()->vertex();
					VertexIter v1 = curr->halfedge()->twin()->vertex();
					
					if((v0->position - v1->position).norm2() >= SHORT_EDGE_2 * mean2)
						continue;
					
					HalfedgeIter h = v0->halfedge();
					do
					{
						if(edgeSet.find(h->edge()) != edgeSet.end())
							edgeSet.erase(h->edge());
						h = h->twin()->next();
					}
					while(h != v0->halfedge());
					
					h = v1->halfedge();
					do
					{
						if(edgeSet.find(h->edge()) != edgeSet.end())
							edgeSet.erase(h->edge());
						h = h->twin()->next();
					}
					while(h != v1->halfedge());
					
					VertexIter v_new = mesh.collapseEdge(curr);
					if(v_new != mesh.verticesEnd())
					{
						h = v_new->halfedge();
						do
						{
							edgeSet.insert(h->edge());
							h = h->twin()->next();
						}
						while(h != v_new->halfedge());
					}
				}
				
				// TODO Now flip each edge if it improves vertex degree
				for(auto edge = mesh.edgesBegin(); edge != mesh.edgesEnd(); ++edge)
				{
					if(willFlipEdgeImprove(edge))
						mesh.flipEdge(edge);
				}

//				 TODO Finally, apply some tangential smoothing to the vertex positions

				for(int j = 0; j < SMOOTH_TIMES; ++j)
				{
					for(auto vertex = mesh.verticesBegin(); vertex != mesh.verticesEnd(); ++vertex)
					{
						if(vertex->isBoundary())
							continue;
						vertex->computeCentroid();
					}
					
					for(auto vertex = mesh.verticesBegin(); vertex != mesh.verticesEnd(); ++vertex)
					{
						if(vertex->isBoundary())
							continue;
						Vector3D dir = vertex->centroid - vertex->position;
						Vector3D nrm = vertex->normal();
						dir -= (dot(nrm, dir) * nrm);
						vertex->position = vertex->position + WEIGHT_FACTOR * dir;
					}
				}

			}

   }
Пример #22
0
bool SelectionEditor::modify(EAlteration alter, SelectionDirection direction, TextGranularity granularity, EUserTriggered userTriggered)
{
    if (userTriggered == UserTriggered) {
        OwnPtrWillBeRawPtr<FrameSelection> trialFrameSelection = FrameSelection::create();
        trialFrameSelection->setSelection(m_selection);
        trialFrameSelection->modify(alter, direction, granularity, NotUserTriggered);

        if (trialFrameSelection->selection().isRange() && m_selection.isCaret() && !dispatchSelectStart())
            return false;
    }

    willBeModified(alter, direction);

    bool wasRange = m_selection.isRange();
    VisiblePosition originalStartPosition = m_selection.visibleStart();
    VisiblePosition position;
    switch (direction) {
    case DirectionRight:
        if (alter == FrameSelection::AlterationMove)
            position = modifyMovingRight(granularity);
        else
            position = modifyExtendingRight(granularity);
        break;
    case DirectionForward:
        if (alter == FrameSelection::AlterationExtend)
            position = modifyExtendingForward(granularity);
        else
            position = modifyMovingForward(granularity);
        break;
    case DirectionLeft:
        if (alter == FrameSelection::AlterationMove)
            position = modifyMovingLeft(granularity);
        else
            position = modifyExtendingLeft(granularity);
        break;
    case DirectionBackward:
        if (alter == FrameSelection::AlterationExtend)
            position = modifyExtendingBackward(granularity);
        else
            position = modifyMovingBackward(granularity);
        break;
    }

    if (position.isNull())
        return false;

    if (isSpatialNavigationEnabled(frame())) {
        if (!wasRange && alter == FrameSelection::AlterationMove && position.deepEquivalent() == originalStartPosition.deepEquivalent())
            return false;
    }

    // Some of the above operations set an xPosForVerticalArrowNavigation.
    // Setting a selection will clear it, so save it to possibly restore later.
    // Note: the START position type is arbitrary because it is unused, it would be
    // the requested position type if there were no xPosForVerticalArrowNavigation set.
    LayoutUnit x = lineDirectionPointForBlockDirectionNavigation(START);
    m_selection.setIsDirectional(shouldAlwaysUseDirectionalSelection(frame()) || alter == FrameSelection::AlterationExtend);

    switch (alter) {
    case FrameSelection::AlterationMove:
        m_frameSelection->moveTo(position, userTriggered);
        break;
    case FrameSelection::AlterationExtend:

        if (!m_selection.isCaret()
            && (granularity == WordGranularity || granularity == ParagraphGranularity || granularity == LineGranularity)
            && frame() && !frame()->editor().behavior().shouldExtendSelectionByWordOrLineAcrossCaret()) {
            // Don't let the selection go across the base position directly. Needed to match mac
            // behavior when, for instance, word-selecting backwards starting with the caret in
            // the middle of a word and then word-selecting forward, leaving the caret in the
            // same place where it was, instead of directly selecting to the end of the word.
            VisibleSelection newSelection = m_selection;
            newSelection.setExtent(position);
            if (m_selection.isBaseFirst() != newSelection.isBaseFirst())
                position = m_selection.visibleBase();
        }

        // Standard Mac behavior when extending to a boundary is grow the
        // selection rather than leaving the base in place and moving the
        // extent. Matches NSTextView.
        if (!frame() || !frame()->editor().behavior().shouldAlwaysGrowSelectionWhenExtendingToBoundary()
            || m_selection.isCaret()
            || !isBoundary(granularity)) {
            m_frameSelection->setExtent(position, userTriggered);
        } else {
            TextDirection textDirection = directionOfEnclosingBlock();
            if (direction == DirectionForward || (textDirection == LTR && direction == DirectionRight) || (textDirection == RTL && direction == DirectionLeft))
                m_frameSelection->setEnd(position, userTriggered);
            else
                m_frameSelection->setStart(position, userTriggered);
        }
        break;
    }

    if (granularity == LineGranularity || granularity == ParagraphGranularity)
        m_xPosForVerticalArrowNavigation = x;

    return true;
}
Пример #23
0
bool SelectionModifier::modify(EAlteration alter,
                               SelectionDirection direction,
                               TextGranularity granularity) {
  DCHECK(!frame()->document()->needsLayoutTreeUpdate());
  DocumentLifecycle::DisallowTransitionScope disallowTransition(
      frame()->document()->lifecycle());

  willBeModified(alter, direction);

  bool wasRange = m_selection.isRange();
  VisiblePosition originalStartPosition = m_selection.visibleStart();
  VisiblePosition position;
  switch (direction) {
    case DirectionRight:
      if (alter == FrameSelection::AlterationMove)
        position = modifyMovingRight(granularity);
      else
        position = modifyExtendingRight(granularity);
      break;
    case DirectionForward:
      if (alter == FrameSelection::AlterationExtend)
        position = modifyExtendingForward(granularity);
      else
        position = modifyMovingForward(granularity);
      break;
    case DirectionLeft:
      if (alter == FrameSelection::AlterationMove)
        position = modifyMovingLeft(granularity);
      else
        position = modifyExtendingLeft(granularity);
      break;
    case DirectionBackward:
      if (alter == FrameSelection::AlterationExtend)
        position = modifyExtendingBackward(granularity);
      else
        position = modifyMovingBackward(granularity);
      break;
  }

  if (position.isNull())
    return false;

  if (isSpatialNavigationEnabled(frame())) {
    if (!wasRange && alter == FrameSelection::AlterationMove &&
        position.deepEquivalent() == originalStartPosition.deepEquivalent())
      return false;
  }

  // Some of the above operations set an xPosForVerticalArrowNavigation.
  // Setting a selection will clear it, so save it to possibly restore later.
  // Note: the START position type is arbitrary because it is unused, it would
  // be the requested position type if there were no
  // xPosForVerticalArrowNavigation set.
  LayoutUnit x = lineDirectionPointForBlockDirectionNavigation(START);
  m_selection.setIsDirectional(shouldAlwaysUseDirectionalSelection(frame()) ||
                               alter == FrameSelection::AlterationExtend);

  switch (alter) {
    case FrameSelection::AlterationMove:
      m_selection = createVisibleSelection(
          SelectionInDOMTree::Builder()
              .collapse(position.toPositionWithAffinity())
              .setIsDirectional(m_selection.isDirectional())
              .build());
      break;
    case FrameSelection::AlterationExtend:

      if (!m_selection.isCaret() && (granularity == WordGranularity ||
                                     granularity == ParagraphGranularity ||
                                     granularity == LineGranularity) &&
          frame() &&
          !frame()
               ->editor()
               .behavior()
               .shouldExtendSelectionByWordOrLineAcrossCaret()) {
        // Don't let the selection go across the base position directly. Needed
        // to match mac behavior when, for instance, word-selecting backwards
        // starting with the caret in the middle of a word and then
        // word-selecting forward, leaving the caret in the same place where it
        // was, instead of directly selecting to the end of the word.
        VisibleSelection newSelection = m_selection;
        newSelection.setExtent(position);
        if (m_selection.isBaseFirst() != newSelection.isBaseFirst())
          position = m_selection.visibleBase();
      }

      // Standard Mac behavior when extending to a boundary is grow the
      // selection rather than leaving the base in place and moving the
      // extent. Matches NSTextView.
      if (!frame() ||
          !frame()
               ->editor()
               .behavior()
               .shouldAlwaysGrowSelectionWhenExtendingToBoundary() ||
          m_selection.isCaret() || !isBoundary(granularity)) {
        m_selection.setExtent(position);
      } else {
        TextDirection textDirection = directionOfEnclosingBlock();
        if (direction == DirectionForward ||
            (textDirection == LTR && direction == DirectionRight) ||
            (textDirection == RTL && direction == DirectionLeft))
          setSelectionEnd(&m_selection, position);
        else
          setSelectionStart(&m_selection, position);
      }
      break;
  }

  if (granularity == LineGranularity || granularity == ParagraphGranularity)
    m_xPosForVerticalArrowNavigation = x;

  return true;
}
//! Checks if current index is a boundary.
bool MIcuBreakIterator::isBoundary()
{
    Q_D(MIcuBreakIterator);
    return isBoundary(d->current);
}