Пример #1
0
bool Transform3f::bestFit (int npoints, const Vec3f points[], const Vec3f goals[], float *sqsum_out)
{
   QS_DEF(Array<double>, X); //set of points
   QS_DEF(Array<double>, Y); //set of goals
   Matr3x3d R, RT, RTR, evectors_matrix;
   //
   Matr3x3d rotation;
   double scale;
   Vec3f translation;
   //

   bool res = 1;
   Vec3f vec, tmp;
   double cpoints[3] = {0.0}, cgoals[3] = {0.0}; // centroid of points, of goals
   int i, j, k;
   
   for (i = 0; i < npoints; i++)
   {
      cpoints[0] += points[i].x;
      cpoints[1] += points[i].y;
      cpoints[2] += points[i].z;
      cgoals[0] += goals[i].x;
      cgoals[1] += goals[i].y;
      cgoals[2] += goals[i].z;
   }
   for (i = 0; i < 3; i++)
   {
      cpoints[i] /= npoints; 
      cgoals[i] /= npoints;
   }
   X.resize(npoints * 3);
   Y.resize(npoints * 3);

   //move each set to origin
   for (i = 0; i < npoints; i++)
   {
      X[i * 3 + 0] = points[i].x - cpoints[0];
      X[i * 3 + 1] = points[i].y - cpoints[1];
      X[i * 3 + 2] = points[i].z - cpoints[2];
      Y[i * 3 + 0] = goals[i].x - cgoals[0];
      Y[i * 3 + 1] = goals[i].y - cgoals[1];
      Y[i * 3 + 2] = goals[i].z - cgoals[2];
   }

   if (npoints > 1)
   {
      /* compute R */
      for (i = 0; i < 3; i++) 
      {
         for (j = 0; j < 3; j++) 
         {
            R.elements[i * 3 + j] = 0.0;
            for (k = 0; k < npoints; k++)
            {
               R.elements[i * 3 + j] += Y[k * 3 + i] * X[k * 3 + j];
            }
         }
      }
      
      //Compute R^T * R

      R.getTransposed(RT);
      RT.matrixMatrixMultiply(R, RTR);

      RTR.eigenSystem(evectors_matrix);

      if (RTR.elements[0] > 2 * EPSILON)
      {
         float norm_b0,norm_b1,norm_b2;
         Vec3f a0, a1, a2;
         Vec3f b0, b1, b2;
         
         a0.set((float)evectors_matrix.elements[0], (float)evectors_matrix.elements[3], (float)evectors_matrix.elements[6]);
         a1.set((float)evectors_matrix.elements[1], (float)evectors_matrix.elements[4], (float)evectors_matrix.elements[7]);
         a2.cross(a0, a1);

         R.matrixVectorMultiply(a0, b0);
         R.matrixVectorMultiply(a1, b1);
         norm_b0 = b0.length();
         norm_b1 = b1.length();
         Line3f l1, l2;
         float sqs1, sqs2;
         l1.bestFit(npoints, points, &sqs1);
         l2.bestFit(npoints, goals, &sqs2);
         if( sqs1 < 2 * EPSILON && sqs2 < 2 * EPSILON)
         {
            Transform3f temp;
            temp.rotationVecVec(l1.dir, l2.dir);
            for (i = 0; i < 3; i++)
               for (j = 0; j < 3; j++)
                  rotation.elements[i * 3 + j] = temp.elements[j * 4 + i];
         }
         else
         {
            b0.normalize();
            b1.normalize();
            b2.cross(b0, b1);
            norm_b2 = b2.length();
            
            evectors_matrix.elements[2] = a2.x;
            evectors_matrix.elements[5] = a2.y;
            evectors_matrix.elements[8] = a2.z;
            evectors_matrix.transpose();
                        
            RTR.elements[0] = b0.x; RTR.elements[1] = b1.x; RTR.elements[2] = b2.x;
            RTR.elements[3] = b0.y; RTR.elements[4] = b1.y; RTR.elements[5] = b2.y;
            RTR.elements[6] = b0.z; RTR.elements[7] = b1.z; RTR.elements[8] = b2.z;
            RTR.matrixMatrixMultiply(evectors_matrix, rotation);
         }
      }
      else
      {
         res = 0;
      }
   }
   else
   {
      res = 0;
   }
   if (!res)
   {
      rotation.identity();
   }
 
   //Calc scale
   scale = 1.0;
   if (res && npoints > 1) 
   {
      float l1 = 0.0;
      float l2 = 0.0;
      Vec3f vx, vy; 
      for (i = 0; i < npoints; i++) 
      {
         Vec3f vx((float)X[i * 3 + 0], (float)X[i * 3 + 1], (float)X[i * 3 + 2]);
         Vec3f vy((float)Y[i * 3 + 0], (float)Y[i * 3 + 1], (float)Y[i * 3 + 2]);
         rotation.matrixVectorMultiply(vx, vec);
         l1 += Vec3f::dot(vy, vec);
         l2 += Vec3f::dot(vec, vec);
      }
      scale = l1 / l2;
   }

   X.clear();
   Y.clear();

   //Calc translation
   translation.set((float)cgoals[0], (float)cgoals[1], (float)cgoals[2]);
   tmp = Vec3f((float)cpoints[0], (float)cpoints[1], (float)cpoints[2]);
   rotation.matrixVectorMultiply(tmp, vec);
   vec.scale((float)scale);
   translation.sub(vec);
   
   identity();
   for (i = 0; i < 3; i++)
   {
      for (j = 0; j < 3; j++)
      {
         elements[i * 4 + j] = (float)rotation.elements[j * 3 + i];
      }
   }
   elements[15] = 1.0f;
   translate(translation);
   for (i = 0; i < 3; i++)
   {
      for (j = 0; j < 3; j++)
      {
         elements[i * 4 + j] *= (float)scale;
      }
   }

   //Deviation
   if (sqsum_out)
   {
      *sqsum_out = 0;
      float d = .0f;
      for (i = 0; i < npoints; i++)
      {
         vec.pointTransformation(points[i], *this);
         d = Vec3f::dist(vec, goals[i]);
         *sqsum_out += d * d;
      }
   }
   return true;
}
Пример #2
0
bool EdgeRotationMatcher::match (float rms_threshold, float eps)
{
   if (cb_get_xyz == 0)
      throw Error("cb_get_xyz not specified");

   if (_subgraph.vertexCount() < 2 || _subgraph.edgeCount() < 1)
      return true;

   QS_DEF(Array<int>, in_cycle);
   QS_DEF(Array<_DirEdge>, edge_queue);
   QS_DEF(Array<int>, vertex_queue);
   QS_DEF(Array<int>, states);

   in_cycle.clear_resize(_subgraph.edgeEnd());
   edge_queue.clear();
   states.clear_resize(__max(_subgraph.edgeEnd(), _subgraph.vertexEnd() + 1));
   
   int i, j, k, bottom;

   // Find all subgraph bridges
   SpanningTree spt(_subgraph, 0);

   in_cycle.zerofill();

   spt.markAllEdgesInCycles(in_cycle.ptr(), 1);

   // Find the first bridge, put it to the queue 2 times
   for (i = _subgraph.edgeBegin(); i < _subgraph.edgeEnd(); i = _subgraph.edgeNext(i))
      if (!in_cycle[i] && (cb_can_rotate == 0 || cb_can_rotate(_subgraph, i)))
      {
         const Edge &edge = _subgraph.getEdge(i);

         if (_mapping[edge.beg] < 0 || _mapping[edge.end] < 0)
            continue;

         edge_queue.push();
         edge_queue.top().idx = i;
         edge_queue.top().beg = edge.beg;
         edge_queue.top().end = edge.end;

         edge_queue.push();
         edge_queue.top().idx = i;
         edge_queue.top().beg = edge.end;
         edge_queue.top().end = edge.beg;
         break;
      }

   // If the queue is empty, then we have no bridge
   if (edge_queue.size() == 0)
   {
      GraphAffineMatcher afm(_subgraph, _supergraph, _mapping);

      afm.cb_get_xyz = cb_get_xyz;
      return afm.match(rms_threshold);
   }

   float scale = 1.f;

   // detect scaling factor by average bond length
   if (equalize_edges)
   {
      float sum_sub = 0.f, sum_super = 0.f;
      
      for (i = _subgraph.edgeBegin(); i < _subgraph.edgeEnd(); i = _subgraph.edgeNext(i))
      {
         const Edge &edge = _subgraph.getEdge(i);
         Vec3f beg, end;

         cb_get_xyz(_subgraph, edge.beg, beg);
         cb_get_xyz(_subgraph, edge.end, end);

         sum_sub += Vec3f::dist(beg, end);
      }

      for (i = _supergraph.edgeBegin(); i < _supergraph.edgeEnd(); i = _supergraph.edgeNext(i))
      {
         const Edge &edge = _supergraph.getEdge(i);
         Vec3f beg, end;

         cb_get_xyz(_supergraph, edge.beg, beg);
         cb_get_xyz(_supergraph, edge.end, end);

         sum_super += Vec3f::dist(beg, end);
      }

      if (sum_sub > EPSILON && sum_super > EPSILON)
      {
         sum_sub /= _subgraph.edgeCount();
         sum_super /= _supergraph.edgeCount();
         scale = sum_super / sum_sub;
      }
   }

   // save vertex positions

   QS_DEF(Array<Vec3f>, xyz_sub);
   QS_DEF(Array<Vec3f>, xyz_super);
   QS_DEF(Array<int>, xyzmap);

   xyzmap.clear_resize(_supergraph.vertexEnd());
   xyz_sub.clear();
   xyz_super.clear();

   for (i = _subgraph.vertexBegin(); i != _subgraph.vertexEnd();
        i = _subgraph.vertexNext(i))
   {
      if (_mapping[i] < 0)
         continue;

      Vec3f &pos_sub   = xyz_sub.push();
      Vec3f &pos_super = xyz_super.push();

      cb_get_xyz(_subgraph, i, pos_sub);
      cb_get_xyz(_supergraph, _mapping[i], pos_super);

      pos_sub.scale(scale);

      xyzmap[_mapping[i]] = xyz_sub.size() - 1;
   }

   // Make queue of edges
   states.zerofill();
   bottom = 0;

   while (edge_queue.size() != bottom)
   {
      // extract edge from queue
      int edge_end = edge_queue[bottom].end;
      int edge_idx = edge_queue[bottom].idx;
      bottom++;
      
      // mark it as 'completed'
      states[edge_idx] = 2;

      // look for neighbors
      const Vertex &end_vertex = _subgraph.getVertex(edge_end);

      for (i = end_vertex.neiBegin(); i != end_vertex.neiEnd(); i = end_vertex.neiNext(i))
      {
         int nei_edge_idx = end_vertex.neiEdge(i);

         // check that neighbor have 'untouched' status
         if (states[nei_edge_idx] != 0)
            continue;

         const Edge &nei_edge = _subgraph.getEdge(nei_edge_idx);
         int other_end = nei_edge.findOtherEnd(edge_end);

         if (_mapping[other_end] < 0)
            continue;

         // set status 'in process'
         states[nei_edge_idx] = 1;

         // push the neighbor edge to the queue
         edge_queue.push();
         edge_queue.top().idx = nei_edge_idx;
         edge_queue.top().beg = edge_end;
         edge_queue.top().end = other_end;
      }
   }

   // do initial transform (impose first subgraph edge in the queue on corresponding one in the graph)
   int beg2 = edge_queue[0].beg;
   int end2 = edge_queue[0].end;
   int beg1 = _mapping[beg2];
   int end1 = _mapping[end2];
   Vec3f g1_v1, g1_v2, g2_v1, g2_v2, diff1, diff2;
   Transform3f matr;

   cb_get_xyz(_supergraph, beg1, g1_v1);
   cb_get_xyz(_supergraph, end1, g1_v2);

   cb_get_xyz(_subgraph, beg2, g2_v1);
   cb_get_xyz(_subgraph, end2, g2_v2);

   g2_v1.scale(scale);
   g2_v2.scale(scale);

   diff1.diff(g1_v2, g1_v1);
   diff2.diff(g2_v2, g2_v1);

   matr.identity();
   if (!matr.rotationVecVec(diff2, diff1))
      throw Error("error calling RotationVecVec()");

   matr.translateLocal(-g2_v1.x, -g2_v1.y, -g2_v1.z);
   matr.translate(g1_v1);

   for (k = 0; k < xyz_sub.size(); k++)
      xyz_sub[k].transformPoint(matr);

   // for all edges in queue that are subject to rotate...
   for (i = 0; i < edge_queue.size(); i++)
   {
      int edge_beg = edge_queue[i].beg;
      int edge_end = edge_queue[i].end;
      int edge_idx = edge_queue[i].idx;

      if (in_cycle[edge_idx])
         continue;

      if (cb_can_rotate != 0 && !cb_can_rotate(_subgraph, edge_idx))
         continue;

      // start BFS from the end of the edge
      states.zerofill();
      states[edge_end] = 1;

      vertex_queue.clear();
      vertex_queue.push(edge_end);
      bottom = 0;

      while (vertex_queue.size() != bottom)
      {
         // extract vertex from queue
         const Vertex &vertex = _subgraph.getVertex(vertex_queue[bottom]);

         states[vertex_queue[bottom]] = 2;
         bottom++;

         // look over neighbors
         for (int j = vertex.neiBegin(); j != vertex.neiEnd(); j = vertex.neiNext(j))
         {
            int nei_idx = vertex.neiVertex(j);

            if (nei_idx == edge_beg)
               continue;
            if (states[nei_idx] != 0)
               continue;
            
            states[nei_idx] = 1;
            vertex_queue.push(nei_idx);
         }
      }

      // now states[j] == 0 if j-th vertex shound not be moved

      Vec3f edge_beg_pos, edge_end_pos, rot_axis;

      // get rotation axis
      edge_beg_pos.copy(xyz_sub[xyzmap[_mapping[edge_beg]]]);
      edge_end_pos.copy(xyz_sub[xyzmap[_mapping[edge_end]]]);

      rot_axis.diff(edge_end_pos, edge_beg_pos);
      if (!rot_axis.normalize())
         continue;

      const Vertex &edge_end_vertex = _subgraph.getVertex(edge_end);

      float max_sum_len = -1;

      for (j = edge_end_vertex.neiBegin(); j != edge_end_vertex.neiEnd();
           j = edge_end_vertex.neiNext(j))
      {
         int nei_idx_2 = edge_end_vertex.neiVertex(j);
         int nei_idx_1 = _mapping[nei_idx_2];

         if (nei_idx_2 == edge_beg)
            continue;

         if (nei_idx_1 == -1)
            continue;

         Vec3f nei1_pos;
         Vec3f nei2_pos;

         nei1_pos.copy(xyz_super[xyzmap[nei_idx_1]]);
         nei2_pos.copy(xyz_sub[xyzmap[_mapping[nei_idx_2]]]);

         nei1_pos.sub(edge_end_pos);
         nei2_pos.sub(edge_end_pos);

         float dot1 = Vec3f::dot(nei1_pos, rot_axis);
         float dot2 = Vec3f::dot(nei2_pos, rot_axis);

         nei1_pos.addScaled(rot_axis, -dot1);
         nei2_pos.addScaled(rot_axis, -dot2);

         if (max_sum_len > nei1_pos.length() + nei1_pos.length())
            continue;

         max_sum_len = nei1_pos.length() + nei1_pos.length();

         if (!nei1_pos.normalize() || !nei2_pos.normalize())
            continue;

         double dp = Vec3f::dot(nei1_pos, nei2_pos);

         if (dp > 1 - EPSILON)
            dp = 1 - EPSILON;
         if (dp < -1 + EPSILON)
            dp = -1 + EPSILON;

         double ang = acos(dp);

         Vec3f cross;

         cross.cross(nei1_pos, nei2_pos);

         if (Vec3f::dot(cross, rot_axis) < 0)
            ang = -ang;

         matr.rotation(rot_axis.x, rot_axis.y, rot_axis.z, (float)ang);
         matr.translateLocalInv(edge_end_pos);
         matr.translate(edge_end_pos);
      }

      if (max_sum_len > 0)
      {
         for (j = _subgraph.vertexBegin(); j < _subgraph.vertexEnd(); j = _subgraph.vertexNext(j))
            if (_mapping[j] >= 0 && states[j] != 0)
               xyz_sub[xyzmap[_mapping[j]]].transformPoint(matr);
      }
   }

   float sqsum = 0;

   for (k = 0; k < xyz_sub.size(); k++)
      sqsum += Vec3f::distSqr(xyz_sub[k], xyz_super[k]);

   sqsum = sqrt(sqsum / xyz_sub.size());

   if (sqsum > rms_threshold + eps)
      return false;

   return true;
}