void gldraw(const std::vector<float3> &verts, const std::vector<int3> &tris) { glBegin(GL_TRIANGLES); glColor4f(1, 1, 1, 0.25f); for (auto t : tris) { auto n = TriNormal(verts[t[0]], verts[t[1]], verts[t[2]]); glNormal3fv(n); auto vn = vabs(n); int k = argmax(&vn.x, 3); for (int j = 0; j < 3; j++) { const auto &v = verts[t[j]]; glTexCoord2f(v[(k + 1) % 3], v[(k + 2) % 3]); glVertex3fv(v); } } glEnd(); }
msym_error_t partitionEquivalenceSets(int length, msym_element_t *elements[length], msym_element_t *pelements[length], msym_geometry_t g, int *esl, msym_equivalence_set_t **es, msym_thresholds_t *thresholds) { int ns = 0, gd = geometryDegenerate(g); double *e = calloc(length,sizeof(double)); double *s = calloc(length,sizeof(double)); int *sp = calloc(length,sizeof(int)); //set partition int *ss = calloc(length,sizeof(int)); //set size double (*ev)[3] = calloc(length,sizeof(double[3])); double (*ep)[3] = calloc(length,sizeof(double[3])); double (*vec)[3] = calloc(length, sizeof(double[3])); double *m = calloc(length, sizeof(double)); for(int i = 0;i < length;i++){ vcopy(elements[i]->v, vec[i]); m[i] = elements[i]->m; } for(int i=0; i < length; i++){ for(int j = i+1; j < length;j++){ double w = m[i]*m[j]/(m[i]+m[j]); double dist; double v[3]; double proji[3], projj[3]; vnorm2(vec[i],v); vproj_plane(vec[j], v, proji); vscale(w, proji, proji); vadd(proji,ep[i],ep[i]); vnorm2(vec[j],v); vproj_plane(vec[i], v, projj); vscale(w, projj, projj); vadd(projj,ep[j],ep[j]); vsub(vec[j],vec[i],v); dist = vabs(v); vscale(w/dist,v,v); vadd(v,ev[i],ev[i]); vsub(ev[j],v,ev[j]); double dij = w*dist; //This is sqrt(I) for a diatomic molecule along an axis perpendicular to the bond with O at center of mass. e[i] += dij; e[j] += dij; s[i] += SQR(dij); s[j] += SQR(dij); } vsub(vec[i],ev[i],ev[i]); } for(int i = 0; i < length; i++){ double v[3]; double w = m[i]/2.0; double dist = vabs(elements[i]->v); double dii = w*dist; vscale(w,elements[i]->v,v); vsub(ev[i],v,ev[i]); // Plane projection can't really differentiate certain types of structures when we add the initial vector, // but not doing so will result in huge cancellation errors on degenerate point groups, // also large masses will mess up the eq check when this is 0. if(gd) vadd(ep[i],v,ep[i]); e[i] += dii; s[i] += SQR(dii); } for(int i = 0; i < length; i++){ if(e[i] >= 0.0){ sp[i] = i; for(int j = i+1; j < length;j++){ if(e[j] >= 0.0){ double vabsevi = vabs(ev[i]), vabsevj = vabs(ev[j]), vabsepi = vabs(ep[i]), vabsepj = vabs(ep[j]); double eep = 0.0, eev = fabs((vabsevi)-(vabsevj))/((vabsevi)+(vabsevj)), ee = fabs((e[i])-(e[j]))/((e[i])+(e[j])), es = fabs((s[i])-(s[j]))/((s[i])+(s[j])); if(!(vabsepi < thresholds->zero && vabsepj < thresholds->zero)){ eep = fabs((vabsepi)-(vabsepj))/((vabsepi)+(vabsepj)); } double max = fmax(eev,fmax(eep,fmax(ee, es))); if(max < thresholds->equivalence && elements[i]->n == elements[j]->n){ e[j] = max > 0.0 ? -max : -1.0; sp[j] = i; } } } e[i] = -1.0; } } for(int i = 0; i < length;i++){ int j = sp[i]; ns += (ss[j] == 0); ss[j]++; } msym_equivalence_set_t *eqs = calloc(ns,sizeof(msym_equivalence_set_t)); msym_element_t **lelements = elements; msym_element_t **pe = pelements; if(elements == pelements){ lelements = malloc(sizeof(msym_element_t *[length])); memcpy(lelements, elements, sizeof(msym_element_t *[length])); } for(int i = 0, ni = 0; i < length;i++){ if(ss[i] > 0){ int ei = 0; eqs[ni].elements = pe; eqs[ni].length = ss[i]; for(int j = 0; j < length;j++){ if(sp[j] == i){ double err = (e[j] > -1.0) ? fabs(e[j]) : 0.0; eqs[ni].err = fmax(eqs[ni].err,err); eqs[ni].elements[ei++] = lelements[j]; } } pe += ss[i]; ni++; } } if(elements == pelements){ free(lelements); } free(m); free(vec); free(s); free(e); free(sp); free(ss); free(ev); free(ep); *es = eqs; *esl = ns; return MSYM_SUCCESS; }
double LabelPosition::getDistanceToPoint( double xp, double yp ) { int i; int j; double mx[4]; double my[4]; double dist_min = DBL_MAX; double dist; for ( i = 0; i < 4; i++ ) { j = ( i + 1 ) % 4; mx[i] = ( x[i] + x[j] ) / 2.0; my[i] = ( y[i] + y[j] ) / 2.0; } if ( vabs( cross_product( mx[0], my[0], mx[2], my[2], xp, yp ) / h ) < w / 2 ) { dist = cross_product( x[1], y[1], x[0], y[0], xp, yp ) / w; if ( vabs( dist ) < vabs( dist_min ) ) dist_min = dist; dist = cross_product( x[3], y[3], x[2], y[2], xp, yp ) / w; if ( vabs( dist ) < vabs( dist_min ) ) dist_min = dist; } if ( vabs( cross_product( mx[1], my[1], mx[3], my[3], xp, yp ) / w ) < h / 2 ) { dist = cross_product( x[2], y[2], x[1], y[1], xp, yp ) / h; if ( vabs( dist ) < vabs( dist_min ) ) dist_min = dist; dist = cross_product( x[0], y[0], x[3], y[3], xp, yp ) / h; if ( vabs( dist ) < vabs( dist_min ) ) dist_min = dist; } for ( i = 0; i < 4; i++ ) { dist = dist_euc2d( x[i], y[i], xp, yp ); if ( vabs( dist ) < vabs( dist_min ) ) dist_min = dist; } if ( nextPart && dist_min > 0 ) return min( dist_min, nextPart->getDistanceToPoint( xp, yp ) ); return dist_min; }