简体   繁体   中英

Determining if two vectors contain two adjacent items the same

I have a problem that concerns determining if two vectors contain two elements the same. The elements may be anywhere in the vector, but they must be adjacent.

EDITED FOR MORE EXAMPLES

For example the following two vectors, when compared, would return false.

Vector 1 = [ 0, 1, 2, 3, 4, 6 ]

Vector 2 = [ 1, 4, 2, 0, 5, 3 ]

But the following two would return true:

Vector 1 = [ 0, 1, 2, 3, 4, 5 ]

Vector 2 = [ 4, 2, 1, 5, 0, 3 ]

because the 1,2 in the first vector would correspond to the 2,1 in the second vector.

True:

Vector 1 = [ 0, 1, 2, 3, 4, 5 ]

Vector 2 = [ 1, 4, 2, 0, 5, 3 ]

{5,0} is a pair, despite looping around the vector (I originally said this was false, thanks for spotting that 'Vlad from Moscow').

True:

Vector 1 = [ 0, 1, 2, 3, 4, 5 ]

Vector 2 = [ 4, 8, 6, 2, 1, 5, 0, 3 ]

{2,1} is still a pair, even though they are not in the same position

The actual application is that I have a polygon (face) with N points stored in a vector. To determine if a set of polygons completely enclose a 3D volume, I test each face to ensure that each edge is shared by another face (where an edge is defined by two adjacent points).

Thus, Face contains a vector of pointers to Points...

std::vector<Point*> points_;

and to check if a Face is surrounded, Face contains a member function...

bool isSurrounded(std::vector<Face*> * neighbours)
{
    int count = 0;
    for(auto&& i : *neighbours)     // for each potential face
        if (i != this)              // that is not this face
            for (int j = 0; j < nPoints(); j++) // and for each point in this face
                for (int k = 0; k < i->nPoints(); k++ ) // check if the neighbour has a shared point, and that the next point (backwards or forwards) is also shared
                    if ( ( this->at(j) == i->at(k) )        // Points are the same, check the next and previous point too to make a pair
                       && (    ( this->at((j+1)%nPoints()) == i->at((k+1)%(i->nPoints())) )
                            || ( this->at((j+1)%nPoints()) == i->at((k+i->nPoints()-1)%(i->nPoints())) )))
                        { count++; }
    if (count > nPoints() - 1) // number of egdes = nPoints -1
        return true;
    else
        return false;
}

Now, obviously this code is horrible. If I come back to this in 2 weeks, I probably won't understand it. So faced with the original problem, how would you neatly check the two vectors?

Note that if you are trying to decipher the provided code. at(int) returns the Point in a face and nPoints() returns the number of points in a face.

Many thanks.

Not efficient but following is a possibility.

bool comparePair ( pair<int,int> p1, pair<int,int> p2 ) {
  return ( p1.first == p2.first && p1.second == p2.second )
           || ( p1.second == p2.first && p1.first == p2.second );
}

//....

vector< pair<int,int> > s1;
vector< pair<int,int> > s1;
vector< pair<int,int> > intersect( vec1.size() + vec2.size() );

for ( int i = 0; i < vec1.size()-1; i++ ) {
  pair<int, int> newPair;
  newPair.first = vec1[i];
  newPair.first = vec1[i+1];
  s1.push_back( newPair );
}

for ( int i = 0; i < vec2.size()-1; i++ ) {
  pair<int, int> newPair;
  newPair.first = vec2[i];
  newPair.first = vec2[i+1];
  s2.push_back( newPair );
}

auto it = std::set_intersection ( s1.begin(), s1.end(), s2.begin(), s2.end(), 
                                   intersect.begin(), comparePair );

return ( it != intersect.begin() ); // not sure about this.

If I understand your question:

std::vector<int> a, b;
std::vector<int>::iterator itB = b.begin();
std::vector<int>::iterator itA;
std::vector<std::vector<int>::iterator> nears;
std::vector<int>::iterator near;
for(;itB!=b.end() ; ++itB) {
    itA = std::find(a.begin(), a.end(), *itB);
    if(nears.empty()) {
        nears.push_back(itA);
    } else {
     /* there's already one it, check the second */  
      if(*(++nears[0])==*itA && itA != a.end() {
        nears.push_back(itA);
      } else {
        nears.clear();
        itB--;
      }         
    }
    if(nears.size() == 2) {
      return true;
    } 
}
return false;
#include <vector>
#include <algorithm>
#include <iterator>
#include <iostream>

using namespace std;
class AdjacentSort
{
public:
    AdjacentSort(const vector<int>& ref);
    ~AdjacentSort();

    bool operator()(int e1,int e2) const;
private:
    const vector<int>& ref_;
};

AdjacentSort::AdjacentSort(const vector<int>& ref):
    ref_(ref)
{
}

bool AdjacentSort::operator()(int e1, int e2) const
{
    auto it1 = find(ref_.begin(),ref_.end(),e1);
    auto it2 = find(ref_.begin(),ref_.end(),e2);

    return distance(it1,it2) == 1;
}

AdjacentSort::~AdjacentSort()
{
}

int main()
{
    vector<int> vec {1,2,3,4,5};
    vector<int> vec2 {1,3,5,4,2};

    AdjacentSort func(vec);
    auto it = adjacent_find(vec2.begin(),vec2.end(),func);

    cout << *it << endl;

    return 0;
}

It returns the first element where two adjacent numbers are found, else it returns the end iterator.

Here is way if your element are same set of elements then assign index for each. (Didnt mention corner cases in pseudo ) :-

for(int i=0;i<vect1.size;i++) {

   adj[vect1[i]][0] = vect1[i-1];
   adj[vect2[i]][1] = vect2[i+1];
}

for(int j=0;j<vect2.size();j++) {

    if(arr[vect2[i]][0]==(vect2[j-1] or vect[j+1]))
       return true
    if(arr[vect2[i]][1]==(vect2[j-1] or vect[j+1]))
       return true

}

If I have understood correctly these two vectors

std::vector<int> v1 = { 0, 1, 2, 3, 4, 5 };
std::vector<int> v2 = { 3, 5, 2, 1, 4, 0 };

contain adjacent equal elements. They are pair {1, 2 } in the first vector and pair { 2, 1 } in the second vector though positions of the pairs are different in the vectors.

In fact you already named the appropriate standard algorithm that can be used in this task. It is std::adjacent_find. For example

#include <iostream>
#include <iomanip>
#include <algorithm>
#include <vector>


int main() 
{
    std::vector<int> v1 = { 0, 1, 2, 3, 4, 5 };
    std::vector<int> v2 = { 3, 5, 2, 1, 4, 0 };

    bool result =
        std::adjacent_find( v1.begin(), v1.end(),
            [&v2]( int x1, int y1 )
            {
                return std::adjacent_find( v2.begin(), v2.end(),
                [=]( int x2, int y2 ) 
                { 
                    return ( x1 == x2 && y1 == y2 || x1 == y2 && y1 == x2 );
                } ) != v2.end();
            } ) != v1.end();

    std::cout << "result = " << std::boolalpha << result << std::endl;

    return 0;
}

Here's my attempt at this problem. Quite simply, iterate through a , find the same element in b and then compare the next element in a with the elements before and after our position in b .

If it's a little wordier than it needed to be it was so that this function can be called with any containers. The only requirement is that the containers' iterators have to bidirectional.

    #include <vector>
    #include <iostream>
    #include <algorithm>
    #include <list>

    using namespace std;

    template <class Iter>
    pair<Iter, Iter> get_neighbors(Iter begin, Iter current, Iter end)
    {
        auto p = make_pair(end, next(current));
        if(current != begin)
            p.first = prev(current);
        return p;
    }

    template <class Iter1, class Iter2>
    bool compare_if_valid(Iter1 p1, Iter1 end1, Iter2 p2)
    {
        return p1 != end1 && *p1 == *p2;
    }

    template <class C1, class C2>
    auto neighbors_match(const C1 & a, const C2 & b) ->
        decltype(make_pair(begin(a), begin(b)))
    {
        for(auto i = begin(a); i != end(a) && next(i) != end(a); ++i)
        {
            auto pos_in_b = find(begin(b), end(b), *i);
            if(pos_in_b != end(b))
            {
                auto b_neighbors = get_neighbors(begin(b), pos_in_b, end(b));
                if(compare_if_valid(b_neighbors.first, end(b), next(i)))
                    return {i, b_neighbors.first};
                else if(compare_if_valid(b_neighbors.second, end(b), next(i)))
                    return {i, pos_in_b};
            }
        }
        return {end(a), end(b)};
    }

    int main()
    {
        vector<int> a = {0, 1, 2, 3, 4, 5};
        vector<int> b = {1, 4, 2, 0, 5, 3};
        cout << boolalpha << (neighbors_match(a, b).first != a.end()) << endl;
        vector<int> a2 = {0, 1, 2, 3, 4, 5};
        list<int> b2 = {4, 2, 1, 5, 0, 3};
        auto match = neighbors_match(a2, b2);
        cout << boolalpha << distance(a2.cbegin(), match.first)
             << ' ' << distance(b2.cbegin(), match.second) << endl;
        return 0;
    }

What you are essentially asking for is whether the edge sets of two faces (let's call them a and b ) are disjoint or not. This can be decomposed into the problem of whether any of the edges in b are in a , which is just a membership test . The issue then, is that vectors are not great at membership tests.

My solution, is to convert one of the vectors into an unordered_set< pair<int, int> > . an unordered_set is just a hash table, and the pairs represent the edges.

In representing edges, I've gone for a normalising scheme where the indices of the vertices are in increasing order (so [2,1] and [1,2] both get stored as [1,2] in my edge set). This makes equality testing that little bit easier (in that it is just the equality of the pair)

So here is my solution:

#include <iostream>
#include <utility>
#include <functional>
#include <vector>
#include <unordered_set>
using namespace std;

using uint = unsigned int;
using pii = pair<int,int>;

// Simple hashing for pairs of integers
struct pii_hash {
    inline size_t
    operator()(const pii & p) const
    {
        return p.first ^ p.second;
    }
};

// Order pairs of integers so the smallest number is first
pii ord_pii(int x, int y) { return x < y ? pii(x, y) : pii(y, x); }

bool
shares_edge(vector<int> a, vector<int> b)
{
    unordered_set<pii, pii_hash> edge_set {};

    // Create unordered set of pairs (the Edge Set)
    for(uint i = 0; i < a.size() - 1; ++i)
        edge_set.emplace( ord_pii(a[i], a[i+1]) );

    // Check if any edges in B are in the Edge Set of A
    for(uint i = 0; i < b.size() - i; ++i)
    {
        pii edge( ord_pii(b[i], b[i+1]) );

        if( edge_set.find(edge) != edge_set.end() )
            return true;
    }

    return false;
}

int main() {
    vector<int>
        a {0, 1, 2, 3, 4, 5},
        b {1, 4, 2, 0, 5, 3},
        c {4, 2, 1, 0, 5, 3};

    shares_edge(a, b); // false
    shares_edge(a, c); // true

    return 0;
}

In your particular case, you may want to make shares_edge a member function of your Face class. It may also be beneficial to precompute the edge set and store it as an instance variable of Face as well, but that depends on how often the edge data changes vs how often this calculation occurs.

EDIT Extra Solution

EDIT 2 Fixed for question change: edge set now wraps around point list.

Here's what it would look like if you added the edge set, precomputed at initialisation to some sort of Face class. The private nested Edge class can be thought of as decorating your current representation of an edge (ie two adjacent positions in the point list), with an actual class, so that collections like sets can treat the index into the point list as an actual edge:

#include <cassert>
#include <iostream>
#include <utility>
#include <functional>
#include <vector>
#include <unordered_set>

using uint = unsigned int;

class Face {
    struct Edge {
        int  _index;
        const std::vector<int> *_vertList;

        Edge(int index, const std::vector<int> *vertList)
            : _index {index}
            , _vertList {vertList}
        {};

        bool
        operator==(const Edge & other) const
        {
            return
                ( elem() == other.elem() && next() == other.next() ) ||
                ( elem() == other.next() && next() == other.elem() );
        }

        struct hash {
            inline size_t
            operator()(const Edge & e) const
            {
                return e.elem() ^ e.next();
            }
        };

    private:
        inline int elem() const { return _vertList->at(_index); }

        inline int
        next() const
        {
            return _vertList->at( (_index + 1) % _vertList->size() );
        }
    };

    std::vector<int>                     _vertList;
    std::unordered_set<Edge, Edge::hash> _edgeSet;

public:

    Face(std::initializer_list<int> verts)
        : _vertList {verts}
        , _edgeSet {}
    {
        for(uint i = 0; i < _vertList.size(); ++i)
            _edgeSet.emplace( Edge(i, &_vertList) );
    }

    bool
    shares_edge(const Face & that) const
    {
        for(const Edge & e : that._edgeSet)
            if( _edgeSet.find(e) != _edgeSet.end() )
                return true;

        return false;
    }

};

int main() {

    Face
        a {0, 1, 2, 3, 4, 5},
        b {1, 4, 2, 0, 5, 3},
        c {4, 2, 1, 0, 5, 3},
        d {0, 1, 2, 3, 4, 6},
        e {4, 8, 6, 2, 1, 5, 0, 3};

    assert( !d.shares_edge(b) );
    assert(  a.shares_edge(b) );
    assert(  a.shares_edge(c) );
    assert(  a.shares_edge(e) );

    return 0;
}

As you can see, this added abstraction makes for a quite pleasing implementation of shares_edge() , but that is because the real trick is in the definition of the Edge class (or to be more specific the relationship that e1 == e2 <=> Edge::hash(e1) == Edge::hash(e2) ).

First, write a make_paired_range_view which takes a range and returns a range whose iterators return std::tie( *it, *std::next(it) ) . boost can help here, as their iterator writing code makes this far less annoying.

Next, unordered_equal takes two pair s and compares them ignoring order (so they are equal if the first both equal and the second both equal, or if the first equals the other second and vice versa).

Now we look for each of the left hand side's pairs in the right hand side using unordered_equal .

This has the advantage of taking 0 extra memory, but the disadvantage of O( n^2 ) time.

If we care more about time than memory, we can instead shove the pair s above into an unordered_set after sorting the pair to be in a canonical order. We then to through the second container, testing each pair (after sorting) to see if it is in the unordered_set . This takes O(n) extra memory, but runs in O(n) time. It can also be done without fancy dancy vector and range writing.

If the elements are more expensive than int , you can write a custom pseudo_pair that holds pointers and whose hash and equality is based on the content of the pointers.

An interesting "how would you do it..." problem... :-) It got me to take a 15 minute break from slapping edit boxes and combo boxes on forms and do a bit of programming for a change... LOL

So, here's how I think I'd do it...

First I'd define a concept of an edge as a pair of values (pair of ints - following your original example). I realize your example is just a simplification and you're actually using vectors of your own classes (Point* rather than int?) but it should be trivial to template-ize this code and use any type you want...

#include <stdlib.h>
#include <iostream>
#include <vector>
#include <set>
#include <vector>
using namespace std;

typedef pair<int, int> edge;

Then I would create a set class that will keep its elements (edges) ordered in the way we need (by comparing edges in the order insensitive manner - ie if e1.first==e2.first and e1.second==e2.second then edges e1 and e2 are the same, but they are also same if e1.first==e2.second and e1.second==e2.first). For this, we could create a functional:

struct order_insensitive_pair_less
{
    bool operator() (const edge& e1, const edge& e2) const
    {
        if(min(e1.first,e1.second)<min(e2.first,e2.second)) return true;
        else if(min(e1.first,e1.second)>min(e2.first,e2.second)) return false;
        else return(max(e1.first,e1.second)<max(e2.first,e2.second));
    }
};

Finally, our helper class (call it edge_set) would be a simple derivative of a set ordered using the above functional with a couple of convenience methods added - a constructor that populates the set from a vector (or your Face class in practice) and a tester function (bool shares_edge(const vector&v)) that tells us whether or not the set shares an edge with another. So:

struct edge_set : public set<edge, order_insensitive_pair_less>
{
    edge_set(const vector<int>&v);
    bool shares_edge(const vector<int>&v);
};

Implemented as:

edge_set::edge_set(const std::vector<int>&v) : set<edge, order_insensitive_pair_less>()
{
    if(v.size()<2) return; // assume there must be at least 2 elements in the vector since it is supposed to be a list of edges...
    for (std::vector<int>::const_iterator it = v.begin()+1; it != v.end(); it++)
        insert(edge(*(it-1), *it));
}

bool edge_set::shares_edge(const std::vector<int>& v)
{
    edge_set es(v);
    for(iterator es_it = begin(); es_it != end(); es_it++)
        if(es.count(*es_it))
            return true;
    return false;
}

The usage then becomes trivial (and reasonably elegant). Assuming you have the two vectors you gave as examples in the abstract of your problem in variables v1 and v2, to test whether they share an edge you would just write:

if(edge_set(v1).shares_edge(v2))
    // Yup, they share an edge, do something about it...
else
    // Nope, not these two... Do something different...

The only assumption about the number of elements in this approach is that each vector will have at least 2 (since you cannot have an "edge" without at least to vertices). However, even if this is not the case (one of the vectors is empty or has just one element) - this will result in an empty edge_set so you'll just get an answer that they have no shared edges (since one of the sets is empty). No big deal... In my opinion, doing it this way would certainly pass the "two week test" since you would have a dedicated class where you could have a couple of comment lines to say what it's doing and the actual comparison is pretty readable (edge_set(v1).shares_edge(v2))...

I think this is the most concise i can come up with.

bool check_for_pairs(std::vector<int> A, std::vector<int> B) {
  auto lastA = A.back();
  for (auto a : A) {
    auto lastB = B.back();
    for (auto b : B) {
      if ((b == a && lastB == lastA) || (b == lastA && lastB == a)) return true;
      lastB = b;
    }
    lastA = a;
  }
  return false;
}

Are more time efficient approach would be to use a set

bool check_for_pairs2(std::vector<int> A, std::vector<int> B) {
  using pair = std::pair<int,int>;
  std::unordered_set< pair, boost::hash<pair> > lookup;
  auto last = A.back();
  for (auto a : A) {
    lookup.insert(a < last ? std::make_pair(a,last) : std::make_pair(last,a));
    last = a;
  }
  last = B.back();
  for (auto b : B) {
    if (lookup.count(b < last ? std::make_pair(b,last) : std::make_pair(last,b)))
      return true;
    last = b;
  }
  return false;
}

If you implement a hash function that hashes (a,b) and (b,a) to the same, you could remove the check for which value is smallest

I know I'm a little late with this, but here's my take at it:

Not in-situ:

#include <algorithm>
#include <iostream>
#include <tuple>
#include <vector>

template<typename Pair>
class pair_generator {
public:
    explicit pair_generator(std::vector<Pair>& cont)
    : cont_(cont)
    { }

    template<typename T>
    bool operator()(T l, T r) {
        cont_.emplace_back(r, l);
        return true;
    }
private:
    std::vector<Pair>& cont_;
};

template<typename Pair>
struct position_independant_compare {

    explicit position_independant_compare(const Pair& pair)
    : pair_(pair)
    { }

    bool operator()(const Pair & p) const {
        return (p.first == pair_.first && p.second == pair_.second) || (p.first == pair_.second && p.second == pair_.first);
    }
private:
    const Pair& pair_;
};

template<typename T>
using pair_of = std::pair<T, T>;

template<typename T>
std::ostream & operator <<(std::ostream & stream, const pair_of<T>& pair) {
    return stream << '[' << pair.first << ", " << pair.second << ']';
}

int main() {
    std::vector<int>
        v1 {0 ,1, 2, 3, 4, 5},
        v2 {4, 8, 6, 2, 1, 5, 0, 3};

    std::vector<pair_of<int> >
        p1 { },
        p2 { };

    // generate our pairs
    std::sort(v1.begin(), v1.end(), pair_generator<pair_of<int>>{ p1 });
    std::sort(v2.begin(), v2.end(), pair_generator<pair_of<int>>{ p2 });

    // account for the fact that the first and last element are a pair too
    p1.emplace_back(p1.front().first, p1.back().second);
    p2.emplace_back(p2.front().first, p2.back().second);

    std::cout << "pairs for vector 1" << std::endl;
    for(const auto & p : p1) { std::cout << p << std::endl; }

    std::cout << std::endl << "pairs for vector 2" << std::endl;
    for(const auto & p : p2) { std::cout << p << std::endl; }

    std::cout << std::endl << "pairs shared between vector 1 and vector 2" << std::endl;
    for(const auto & p : p1) {
        const auto pos = std::find_if(p2.begin(), p2.end(), position_independant_compare<pair_of<int>>{ p });
        if(pos != p2.end()) {
            std::cout << p << std::endl;
        }
    }
}

Example output on ideone

In-situ:

#include <algorithm>
#include <iostream>
#include <iterator>
#include <tuple>
#include <vector>

template<typename T>
struct in_situ_pair
: std::iterator<std::forward_iterator_tag, T> {

    using pair = std::pair<T, T>;

    in_situ_pair(std::vector<T>& cont, std::size_t idx)
    : cont_(cont), index_{ idx }
    { }

    pair operator*() const {
        return { cont_[index_], cont_[(index_ + 1) % cont_.size()] };
    }

    in_situ_pair& operator++() {
        ++index_;
        return *this;
    }

    bool operator==(const pair& r) const {
        const pair l = operator*();
        return  (l.first == r.first && l.second == r.second)
                || (l.first == r.second && l.second == r.first);
    }

    bool operator==(const in_situ_pair& o) const {
        return (index_ == o.index_);
    }

    bool operator!=(const in_situ_pair& o) const {
        return !(*this == o);
    }
public:
    friend bool operator==(const pair& l, const in_situ_pair& r) {
        return (r == l);
    }
private:
    std::vector<T>& cont_;
    std::size_t index_;
};

template<typename T>
using pair_of = std::pair<T, T>;

template<typename T>
std::ostream & operator <<(std::ostream & stream, const pair_of<T>& pair) {
    return stream << '[' << pair.first << ", " << pair.second << ']';
}

namespace in_situ {
    template<typename T>
    in_situ_pair<T> begin(std::vector<T>& cont) { return { cont, 0 }; }

    template<typename T>
    in_situ_pair<T> end(std::vector<T>& cont) { return { cont, cont.size() }; }

    template<typename T>
    in_situ_pair<T> at(std::vector<T>& cont, std::size_t i) { return { cont, i }; }
}

int main() {
    std::vector<int>
        v1 {0 ,1, 2, 3, 4, 5},
        v2 {4, 8, 6, 2, 1, 5, 0, 3};

    for(std::size_t i = 0; i < v1.size(); ++i) {
        auto pos = std::find(in_situ::begin(v2), in_situ::end(v2), in_situ::at(v1, i));
        if(pos != in_situ::end(v2)) {
            std::cout << "common: " << *pos << std::endl;
        }
    }
}

Example output on ideone

There have been a lot of great answers, and I'm sure people searching for the general problem of looking for adjacent pairs of equal elements in two vectors will find them enlightening. I have decided to answer my own question because I think a neater version of my original attempt is the best answer for me .

Since there doesn't seem to be a combination of std algorithms that make the methodology simpler, I believe looping and querying each element to be the most concise and understandable.

Here is the algorithm for the general case:

std::vector<int> vec1 = { 1, 2, 3, 4, 5, 6 };
std::vector<int> vec2 = { 3, 1, 4, 2, 6, 5 };

// Loop over the elements in the first vector, looking for an equal element in the 2nd vector
for(int i = 0; i < vec1.size(); i++) for(int j = 0; j < vec2.size(); j++)
    if ( vec1[i] == vec2[j] &&
        // ... Found equal elements, now check if the next element matches the next or previous element in the other vector
        ( vec1[(i+1) % vec1.size()] == vec2[(j+1) % vec2.size()]
        ||vec1[(i+1) % vec1.size()] == vec2[(j-1+vec2.size()) % vec2.size()] ) )
        return true;
return false;

Or in my specific case, where I am actually checking a vector of vectors, and where the elements are no longer ints, but pointers to a class.

(The operator[] of the Face class returns an element of a vector belonging to the face).

bool isSurrounded(std::vector<Face*> * neighbours)
{
    // We can check if each edge aligns with an edge in a nearby face,
    // ... if each edge aligns, then the face is surrounded
    // ... an edge is defined by two adjacent points in the points_ vector
    // ... so we check for two consecutive points to be equal...
    int count = 0;
    // for each potential face that is not this face
    for(auto&& i : *neighbours) if (i != this)
        // ... loop over both vectors looking for an equal point
        for (int j = 0; j < nPoints(); j++) for (int k = 0; k < i->nPoints(); k++ )
            if ( (*this)[j] == (*i)[k] &&
                // ... equal points have been found, check if the next or previous points also match
               (  (*this)[(j+1) % nPoints()] == (*i)[(k+1) % i->nPoints()]
               || (*this)[(j+1) % nPoints()] == (*i)[(k-1+i->nPoints()) % i->nPoints()] ) )
               // ... an edge is shared
                { count++; }
    // number of egdes = nPoints -1
    if (count > nPoints() - 1)
        return true;
    else
        return false;
}

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM