void snlSurfaceOfRevolution::vertexNet ( snlVertexNet* vNet, double tolerance, bool parametric ) { // Return approximation to surface. // -------------------------------- // tolerance: Tolerance to approximate to. // parametric: Do a parametric analysis as opposed to knot refinement. // vNet: Vertex net to fill with data. snlCurve* profileCopy = new snlCurve ( *profile ); if ( tolerance > 0.0 ) profileCopy -> refine ( tolerance ); const snlCtrlPoint* ctrlPts = profileCopy -> controlPointNet().getCtrlPts(); int numPts = profileCopy -> controlPointNet().size(); vNet -> vertexNet ( ctrlPts, numPts ); // Find angle step to use. snlPoint axis_start_norm ( *axis_start ); axis_start_norm.normalise(); snlPoint axis_end_norm ( *axis_end ); axis_end_norm.normalise(); // Get largest radius double maxRadius = 0.0; for ( int index = 0; index < numPts; index ++ ) { double dist = distToLine ( axis_start_norm, axis_end_norm, ctrlPts [ index ] ); if ( dist > maxRadius ) maxRadius = dist; } // Calculate steps based on tolerance and maximum radius. double angleStep = 2 * acos ( 1.0 - ( tolerance / maxRadius ) ); int numSteps = (int ) ( rot_angle / angleStep ) + 1; angleStep = rot_angle / (double) numSteps; // Rotate and append points at discrete angle steps. snlTransform transf; transf.rotate ( angleStep, axis_start_norm, axis_end_norm ); for ( int step = 0; step < numSteps; step ++ ) { profileCopy -> controlPointNet().transform ( transf ); vNet -> appendRow ( ctrlPts ); } }
// Closest point to line segment between a and b (OK if a == b) double distToLineSegment(point p, point a, point b, point &c) { vec ap = toVec(a, p), ab = toVec(a, b); double u = dot(ap, ab) / norm_sq(ab); if (u < 0.0) { c = point(a.x, a.y); return dist(p, a); } if (u > 1.0) { c = point(b.x, b.y); return dist(p, b); } return distToLine(p, a, b, c); }
// returns the distance from p to the line segment ab defined by two points a and b. The closest point is stored in c. ftype distToLineSegment(const Point& p, const Point& a, const Point& b, Point& c) { Vec ap(a, p), ab(a, b); ftype u = ap.dot(ab) / ab.norm_sq(); if (u < 0.0) { // closer to a c = a; return dist(p, a); // Euclidean distance between p and a } else if (u > 1.0) { // closer to b c = b; return dist(p, b); // Euclidean distance between p and b } return distToLine(p, a, b, c); }
// Distance from a point to a line segment // Returns the distance from p to the line segment ab. // The closest point on ab is returned through (cpx, cpy). // Works correctly for degenerate line segments (a == b). // REQUIRES: #include <math.h>, #define EPS ..., dist(), distToLine() double distToLineSegment(double ax, double ay, double bx, double by, double px, double py, double *cpx, double *cpy) { if ((bx - ax) * (px - ax) + (by - ay) * (py - ay) < EPS) { *cpx = ax; *cpy = ay; return dist(ax, ay, px, py); } if ((ax - bx) * (px - bx) + (ay - by) * (py - by) < EPS) { *cpx = bx; *cpy = by; return dist(bx, by, px, py); } return distToLine(ax, ay, bx, by, px, py, cpx, cpy); }
void NodeConnectionControl::onDrag(APoint m_pos, AVec d_pos) { if(fromNode && toNode) { APoint m_pos_grid = m_pos + pos; float dist = distToLine(m_pos); //std::cout << dist << "\n"; //std::cout << "(" << pTo.x << ", " << pTo.y << "), (" << pFrom.x << ", " << pFrom.y << "), (" << m_pos.x << ", " << m_pos.y << ")\n"; //std::cout << dist << " (" << disconnectRadius << ")\n"; if(dist > disconnectRadius || !pointInside(m_pos)) { AVec d_pos_from = pFrom - m_pos, d_pos_to = pTo - m_pos; float to_dist_2 = d_pos_to.x*d_pos_to.x + d_pos_to.y*d_pos_to.y, from_dist_2 = d_pos_from.x*d_pos_from.x + d_pos_from.y*d_pos_from.y; AStatus status = fromNc->disconnect(toNc); if(!statusGood(status)) { std::cout << status << "\n"; return; } if(to_dist_2 < from_dist_2) { toNode = nullptr; toNc = nullptr; ngd_parent->restartConnectingNodes(this, fromNode, fromNc->getId()); } else { fromNode = nullptr; fromNc = nullptr; ngd_parent->restartConnectingNodes(this, toNode, toNc->getId()); } setHangingPos(m_pos); } } }
void snlCircularOffsetCurve::applyOffset ( snlPoint& point, snlPoint chordOffset, snlPoint angleOffset, snlPoint tangentOffset ) const { // Rotate point about axis by circular offset. // ------------------------------------------- // point: Point to rotate. // chordOffset: Point containing weighted chord offset. // angleOffset: Point containing weighted angle offset. // tangentOffset: Point containing weighted tangent offset. chordOffset.normalise(); angleOffset.normalise(); tangentOffset.normalise(); double angle = 0.0; // Calculate angle to rotate by by adding all offsets together. double dist = distToLine ( *axis_start, *axis_end, point ); // CHORD. if ( chordOffset.x() != 0.0 ) angle = chordOffset.x() / dist; // ANGLE. angle += angleOffset.x(); // TANGENT. if ( tangentOffset.x() != 0.0 ) { angle += asin ( tangentOffset.x() / dist ); } // Apply angle. if ( angle != 0.0 ) { snlTransform transf; transf.rotate ( angle, *axis_start, *axis_end ); transf.transform ( point ); } }
bool NodeConnectionControl::respondToClick(APoint m_pos, MouseButton b) { return fromNode && toNode && (distToLine(m_pos) <= activeRadius); //return (controlState == ControlState::HOVERING); }
bool NodeConnectionControl::respondToMouse(APoint m_pos) { return controlState == ControlState::CLICKING || controlState == ControlState::DRAGGING || (fromNode && toNode && (distToLine(m_pos) <= activeRadius)); }
void Level::fixCoordsWithObj(LevelObj& obj, Actor* act)// f32& xx, f32& yy, f32& vx, f32& vy, f32& gx, f32& gy) { obj.state = 1; f32 px = act->x+act->gvx*2; f32 py = act->y+act->gvy*2; int dists[4]; dists[0] = distToLine(px, py, obj.x[0], obj.y[0], obj.x[1], obj.y[1]).toint(); dists[1] = distToLine(px, py, obj.x[1], obj.y[1], obj.x[2], obj.y[2]).toint(); dists[2] = distToLine(px, py, obj.x[2], obj.y[2], obj.x[3], obj.y[3]).toint(); dists[3] = distToLine(px, py, obj.x[3], obj.y[3], obj.x[0], obj.y[0]).toint(); int best1 = -1; int bestd; for(int i = 0; i < 4; i++) if((dists[i] < bestd || best1 == -1)) bestd=dists[i], best1 = i; int best2 = -1; for(int i = 0; i < 4; i++) if((dists[i] < bestd || best2 == -1) && i != best1) bestd=dists[i], best2 = i; bool invalid1 = obj.neighbors[best1] != -1; bool invalid2 = obj.neighbors[best2] != -1; if(invalid1 && invalid2) //Corner: Just collide with the neighbor fixCoordsWithObj(objs->objs[obj.neighbors[best1]], act); else { if(invalid1) { best1 = best2; invalid1 = invalid2; } int n = best1; int n2 = (n+1)%4; f32 oldx = act->x; projectToLine(act->x, act->y, obj.x[n], obj.y[n], obj.x[n2], obj.y[n2]); f32 fx, fy; fx = act->vx; fy = act->vy; projectVecToLine(fx, fy, obj.y[n2], obj.x[n], obj.y[n], obj.x[n2]); bool bounce = obj.type == BEH_BOUNCY || (fabs(fx)+fabs(fy))>8; if(!bounce) { projectVecToLine(act->vx, act->vy, obj.x[n], obj.y[n], obj.x[n2], obj.y[n2]); fx = -(obj.y[n2]-obj.y[n]); fy = obj.x[n2]-obj.x[n]; vecNormalize(fx, fy); act->gx = fx; act->gy = fy; if(fabs(act->gx) < 0.4) { act->gx = 0; // act->vx = 0; act->x = oldx; } act->x += act->gx; act->y += act->gy; } else { addSparkles(obj); fx = act->vx; fy = act->vy; f32 nx = -(obj.y[n2]-obj.y[n]); f32 ny = obj.x[n2]-obj.x[n]; vecNormalize(nx, ny); f32 dotp = -fx*nx-fy*ny; fx = fx+nx*dotp*2; fy = fy+ny*dotp*2; if(obj.type != BEH_BOUNCY) { fx /= 2; fy /= 2; } else { fx *= f32(1.7); fy *= f32(1.7); } act->vx = fx + nx/2; act->vy = fy + ny/2; act->x += nx*3; act->y += ny*3; } } }