mirror of
https://github.com/JulianGro/overte.git
synced 2025-05-02 07:25:39 +02:00
Minimum chat circle radius from Ryan, basic avatar/voxel orbit behavior.
This commit is contained in:
parent
1003393101
commit
aa9fc290a5
10 changed files with 135 additions and 12 deletions
|
@ -1105,9 +1105,24 @@ void Application::mouseMoveEvent(QMouseEvent* event) {
|
||||||
}
|
}
|
||||||
|
|
||||||
if (activeWindow() == _window) {
|
if (activeWindow() == _window) {
|
||||||
|
int deltaX = event->x() - _mouseX;
|
||||||
|
int deltaY = event->y() - _mouseY;
|
||||||
|
|
||||||
_mouseX = event->x();
|
_mouseX = event->x();
|
||||||
_mouseY = event->y();
|
_mouseY = event->y();
|
||||||
|
|
||||||
|
// orbit behavior
|
||||||
|
if (_mousePressed && !Menu::getInstance()->isVoxelModeActionChecked()) {
|
||||||
|
if (_lookatTargetAvatar) {
|
||||||
|
_myAvatar.orbit(_lookatTargetAvatar->getPosition(), deltaX, deltaY);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
if (_isHoverVoxel) {
|
||||||
|
_myAvatar.orbit(glm::vec3(_hoverVoxel.x, _hoverVoxel.y, _hoverVoxel.z) * (float)TREE_SCALE, deltaX, deltaY);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
// detect drag
|
// detect drag
|
||||||
glm::vec3 mouseVoxelPos(_mouseVoxel.x, _mouseVoxel.y, _mouseVoxel.z);
|
glm::vec3 mouseVoxelPos(_mouseVoxel.x, _mouseVoxel.y, _mouseVoxel.z);
|
||||||
if (!_justEditedVoxel && mouseVoxelPos != _lastMouseVoxelPos) {
|
if (!_justEditedVoxel && mouseVoxelPos != _lastMouseVoxelPos) {
|
||||||
|
@ -1151,7 +1166,8 @@ void Application::mousePressEvent(QMouseEvent* event) {
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!_palette.isActive() && (!_isHoverVoxel || _lookatTargetAvatar)) {
|
if (!_palette.isActive() && (!_isHoverVoxel || _lookatTargetAvatar)) {
|
||||||
_pieMenu.mousePressEvent(_mouseX, _mouseY);
|
// disable for now
|
||||||
|
// _pieMenu.mousePressEvent(_mouseX, _mouseY);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (Menu::getInstance()->isOptionChecked(MenuOption::VoxelSelectMode) && _pasteMode) {
|
if (Menu::getInstance()->isOptionChecked(MenuOption::VoxelSelectMode) && _pasteMode) {
|
||||||
|
@ -1952,7 +1968,9 @@ void Application::updateLookatTargetAvatar(const glm::vec3& mouseRayOrigin, cons
|
||||||
bool showWarnings = Menu::getInstance()->isOptionChecked(MenuOption::PipelineWarnings);
|
bool showWarnings = Menu::getInstance()->isOptionChecked(MenuOption::PipelineWarnings);
|
||||||
PerformanceWarning warn(showWarnings, "Application::updateLookatTargetAvatar()");
|
PerformanceWarning warn(showWarnings, "Application::updateLookatTargetAvatar()");
|
||||||
|
|
||||||
_lookatTargetAvatar = findLookatTargetAvatar(mouseRayOrigin, mouseRayDirection, eyePosition, DEFAULT_NODE_ID_REF);
|
if (!_mousePressed) {
|
||||||
|
_lookatTargetAvatar = findLookatTargetAvatar(mouseRayOrigin, mouseRayDirection, eyePosition, DEFAULT_NODE_ID_REF);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
Avatar* Application::findLookatTargetAvatar(const glm::vec3& mouseRayOrigin, const glm::vec3& mouseRayDirection,
|
Avatar* Application::findLookatTargetAvatar(const glm::vec3& mouseRayOrigin, const glm::vec3& mouseRayDirection,
|
||||||
|
@ -1961,17 +1979,15 @@ Avatar* Application::findLookatTargetAvatar(const glm::vec3& mouseRayOrigin, con
|
||||||
NodeList* nodeList = NodeList::getInstance();
|
NodeList* nodeList = NodeList::getInstance();
|
||||||
for (NodeList::iterator node = nodeList->begin(); node != nodeList->end(); node++) {
|
for (NodeList::iterator node = nodeList->begin(); node != nodeList->end(); node++) {
|
||||||
if (node->getLinkedData() != NULL && node->getType() == NODE_TYPE_AGENT) {
|
if (node->getLinkedData() != NULL && node->getType() == NODE_TYPE_AGENT) {
|
||||||
Avatar* avatar = (Avatar *) node->getLinkedData();
|
Avatar* avatar = (Avatar*)node->getLinkedData();
|
||||||
glm::vec3 headPosition = avatar->getHead().getPosition();
|
|
||||||
float distance;
|
float distance;
|
||||||
if (rayIntersectsSphere(mouseRayOrigin, mouseRayDirection, headPosition,
|
if (avatar->findRayIntersection(mouseRayOrigin, mouseRayDirection, distance)) {
|
||||||
HEAD_SPHERE_RADIUS * avatar->getHead().getScale(), distance)) {
|
|
||||||
// rescale to compensate for head embiggening
|
// rescale to compensate for head embiggening
|
||||||
eyePosition = (avatar->getHead().calculateAverageEyePosition() - avatar->getHead().getScalePivot()) *
|
eyePosition = (avatar->getHead().calculateAverageEyePosition() - avatar->getHead().getScalePivot()) *
|
||||||
(avatar->getScale() / avatar->getHead().getScale()) + avatar->getHead().getScalePivot();
|
(avatar->getScale() / avatar->getHead().getScale()) + avatar->getHead().getScalePivot();
|
||||||
|
|
||||||
_lookatIndicatorScale = avatar->getHead().getScale();
|
_lookatIndicatorScale = avatar->getHead().getScale();
|
||||||
_lookatOtherPosition = headPosition;
|
_lookatOtherPosition = avatar->getHead().getPosition();
|
||||||
nodeUUID = avatar->getOwningNode()->getUUID();
|
nodeUUID = avatar->getOwningNode()->getUUID();
|
||||||
return avatar;
|
return avatar;
|
||||||
}
|
}
|
||||||
|
@ -2213,7 +2229,7 @@ void Application::updateHoverVoxels(float deltaTime, glm::vec3& mouseRayOrigin,
|
||||||
glm::vec4 oldVoxel(_hoverVoxel.x, _hoverVoxel.y, _hoverVoxel.z, _hoverVoxel.s);
|
glm::vec4 oldVoxel(_hoverVoxel.x, _hoverVoxel.y, _hoverVoxel.z, _hoverVoxel.s);
|
||||||
// only do this work if MAKE_SOUND_ON_VOXEL_HOVER or MAKE_SOUND_ON_VOXEL_CLICK is enabled,
|
// only do this work if MAKE_SOUND_ON_VOXEL_HOVER or MAKE_SOUND_ON_VOXEL_CLICK is enabled,
|
||||||
// and make sure the tree is not already busy... because otherwise you'll have to wait.
|
// and make sure the tree is not already busy... because otherwise you'll have to wait.
|
||||||
if (!_voxels.treeIsBusy()) {
|
if (!(_voxels.treeIsBusy() || _mousePressed)) {
|
||||||
{
|
{
|
||||||
PerformanceWarning warn(showWarnings, "Application::updateHoverVoxels() _voxels.findRayIntersection()");
|
PerformanceWarning warn(showWarnings, "Application::updateHoverVoxels() _voxels.findRayIntersection()");
|
||||||
_isHoverVoxel = _voxels.findRayIntersection(mouseRayOrigin, mouseRayDirection, _hoverVoxel, distance, face);
|
_isHoverVoxel = _voxels.findRayIntersection(mouseRayOrigin, mouseRayDirection, _hoverVoxel, distance, face);
|
||||||
|
|
|
@ -336,8 +336,24 @@ void Avatar::getSkinColors(glm::vec3& lighter, glm::vec3& darker) {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
bool Avatar::findRayIntersection(const glm::vec3& origin, const glm::vec3& direction, float& distance) const {
|
||||||
|
float minDistance = FLT_MAX;
|
||||||
|
float modelDistance;
|
||||||
|
if (_skeletonModel.findRayIntersection(origin, direction, modelDistance)) {
|
||||||
|
minDistance = qMin(minDistance, modelDistance);
|
||||||
|
}
|
||||||
|
if (_head.getFaceModel().findRayIntersection(origin, direction, modelDistance)) {
|
||||||
|
minDistance = qMin(minDistance, modelDistance);
|
||||||
|
}
|
||||||
|
if (minDistance < FLT_MAX) {
|
||||||
|
distance = minDistance;
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
bool Avatar::findSpherePenetration(const glm::vec3& penetratorCenter, float penetratorRadius,
|
bool Avatar::findSpherePenetration(const glm::vec3& penetratorCenter, float penetratorRadius,
|
||||||
glm::vec3& penetration, int skeletonSkipIndex) {
|
glm::vec3& penetration, int skeletonSkipIndex) const {
|
||||||
bool didPenetrate = false;
|
bool didPenetrate = false;
|
||||||
glm::vec3 totalPenetration;
|
glm::vec3 totalPenetration;
|
||||||
glm::vec3 skeletonPenetration;
|
glm::vec3 skeletonPenetration;
|
||||||
|
|
|
@ -160,6 +160,8 @@ public:
|
||||||
|
|
||||||
void getSkinColors(glm::vec3& lighter, glm::vec3& darker);
|
void getSkinColors(glm::vec3& lighter, glm::vec3& darker);
|
||||||
|
|
||||||
|
bool findRayIntersection(const glm::vec3& origin, const glm::vec3& direction, float& distance) const;
|
||||||
|
|
||||||
/// Checks for penetration between the described sphere and the avatar.
|
/// Checks for penetration between the described sphere and the avatar.
|
||||||
/// \param penetratorCenter the center of the penetration test sphere
|
/// \param penetratorCenter the center of the penetration test sphere
|
||||||
/// \param penetratorRadius the radius of the penetration test sphere
|
/// \param penetratorRadius the radius of the penetration test sphere
|
||||||
|
@ -167,7 +169,7 @@ public:
|
||||||
/// \param skeletonSkipIndex if not -1, the index of a joint to skip (along with its descendents) in the skeleton model
|
/// \param skeletonSkipIndex if not -1, the index of a joint to skip (along with its descendents) in the skeleton model
|
||||||
/// \return whether or not the sphere penetrated
|
/// \return whether or not the sphere penetrated
|
||||||
bool findSpherePenetration(const glm::vec3& penetratorCenter, float penetratorRadius,
|
bool findSpherePenetration(const glm::vec3& penetratorCenter, float penetratorRadius,
|
||||||
glm::vec3& penetration, int skeletonSkipIndex = -1);
|
glm::vec3& penetration, int skeletonSkipIndex = -1) const;
|
||||||
|
|
||||||
virtual int parseData(unsigned char* sourceBuffer, int numBytes);
|
virtual int parseData(unsigned char* sourceBuffer, int numBytes);
|
||||||
|
|
||||||
|
|
|
@ -78,6 +78,7 @@ public:
|
||||||
|
|
||||||
VideoFace& getVideoFace() { return _videoFace; }
|
VideoFace& getVideoFace() { return _videoFace; }
|
||||||
FaceModel& getFaceModel() { return _faceModel; }
|
FaceModel& getFaceModel() { return _faceModel; }
|
||||||
|
const FaceModel& getFaceModel() const { return _faceModel; }
|
||||||
|
|
||||||
const bool getReturnToCenter() const { return _returnHeadToCenter; } // Do you want head to try to return to center (depends on interface detected)
|
const bool getReturnToCenter() const { return _returnHeadToCenter; } // Do you want head to try to return to center (depends on interface detected)
|
||||||
float getAverageLoudness() const { return _averageLoudness; }
|
float getAverageLoudness() const { return _averageLoudness; }
|
||||||
|
|
|
@ -542,6 +542,16 @@ void MyAvatar::loadData(QSettings* settings) {
|
||||||
settings->endGroup();
|
settings->endGroup();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void MyAvatar::orbit(const glm::vec3& position, int deltaX, int deltaY) {
|
||||||
|
glm::vec3 vector = getPosition() - position;
|
||||||
|
glm::quat orientation = getOrientation();
|
||||||
|
glm::vec3 up = orientation * IDENTITY_UP;
|
||||||
|
const float ANGULAR_SCALE = 0.5f;
|
||||||
|
glm::quat rotation = glm::angleAxis(deltaX * -ANGULAR_SCALE, up);
|
||||||
|
const float LINEAR_SCALE = 0.01f;
|
||||||
|
setPosition(position + rotation * vector + up * (deltaY * LINEAR_SCALE * _scale));
|
||||||
|
setOrientation(rotation * orientation);
|
||||||
|
}
|
||||||
|
|
||||||
float MyAvatar::getAbsoluteHeadYaw() const {
|
float MyAvatar::getAbsoluteHeadYaw() const {
|
||||||
return glm::yaw(_head.getOrientation());
|
return glm::yaw(_head.getOrientation());
|
||||||
|
@ -909,8 +919,9 @@ void MyAvatar::updateChatCircle(float deltaTime) {
|
||||||
// remove members whose accumulated circles are too far away to influence us
|
// remove members whose accumulated circles are too far away to influence us
|
||||||
const float CIRCUMFERENCE_PER_MEMBER = 0.5f;
|
const float CIRCUMFERENCE_PER_MEMBER = 0.5f;
|
||||||
const float CIRCLE_INFLUENCE_SCALE = 2.0f;
|
const float CIRCLE_INFLUENCE_SCALE = 2.0f;
|
||||||
|
const float MIN_RADIUS = 0.3f;
|
||||||
for (int i = sortedAvatars.size() - 1; i >= 0; i--) {
|
for (int i = sortedAvatars.size() - 1; i >= 0; i--) {
|
||||||
float radius = (CIRCUMFERENCE_PER_MEMBER * (i + 2)) / PI_TIMES_TWO;
|
float radius = qMax(MIN_RADIUS, (CIRCUMFERENCE_PER_MEMBER * (i + 2)) / PI_TIMES_TWO);
|
||||||
if (glm::distance(_position, sortedAvatars[i].accumulatedCenter) > radius * CIRCLE_INFLUENCE_SCALE) {
|
if (glm::distance(_position, sortedAvatars[i].accumulatedCenter) > radius * CIRCLE_INFLUENCE_SCALE) {
|
||||||
sortedAvatars.remove(i);
|
sortedAvatars.remove(i);
|
||||||
} else {
|
} else {
|
||||||
|
@ -921,7 +932,7 @@ void MyAvatar::updateChatCircle(float deltaTime) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
center = sortedAvatars.last().accumulatedCenter;
|
center = sortedAvatars.last().accumulatedCenter;
|
||||||
float radius = (CIRCUMFERENCE_PER_MEMBER * (sortedAvatars.size() + 1)) / PI_TIMES_TWO;
|
float radius = qMax(MIN_RADIUS, (CIRCUMFERENCE_PER_MEMBER * (sortedAvatars.size() + 1)) / PI_TIMES_TWO);
|
||||||
|
|
||||||
// compute the average up vector
|
// compute the average up vector
|
||||||
glm::vec3 up = getWorldAlignedOrientation() * IDENTITY_UP;
|
glm::vec3 up = getWorldAlignedOrientation() * IDENTITY_UP;
|
||||||
|
|
|
@ -69,6 +69,8 @@ public:
|
||||||
void addThrust(glm::vec3 newThrust) { _thrust += newThrust; };
|
void addThrust(glm::vec3 newThrust) { _thrust += newThrust; };
|
||||||
glm::vec3 getThrust() { return _thrust; };
|
glm::vec3 getThrust() { return _thrust; };
|
||||||
|
|
||||||
|
void orbit(const glm::vec3& position, int deltaX, int deltaY);
|
||||||
|
|
||||||
private:
|
private:
|
||||||
bool _mousePressed;
|
bool _mousePressed;
|
||||||
float _bodyPitchDelta;
|
float _bodyPitchDelta;
|
||||||
|
|
|
@ -546,6 +546,35 @@ glm::vec4 Model::computeAverageColor() const {
|
||||||
return _geometry ? _geometry->computeAverageColor() : glm::vec4(1.0f, 1.0f, 1.0f, 1.0f);
|
return _geometry ? _geometry->computeAverageColor() : glm::vec4(1.0f, 1.0f, 1.0f, 1.0f);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
bool Model::findRayIntersection(const glm::vec3& origin, const glm::vec3& direction, float& distance) const {
|
||||||
|
const glm::vec3 relativeOrigin = origin - _translation;
|
||||||
|
const FBXGeometry& geometry = _geometry->getFBXGeometry();
|
||||||
|
float minDistance = FLT_MAX;
|
||||||
|
float radiusScale = extractUniformScale(_scale);
|
||||||
|
for (int i = 0; i < _jointStates.size(); i++) {
|
||||||
|
const FBXJoint& joint = geometry.joints[i];
|
||||||
|
glm::vec3 end = extractTranslation(_jointStates[i].transform);
|
||||||
|
float endRadius = joint.boneRadius * radiusScale;
|
||||||
|
glm::vec3 start = end;
|
||||||
|
float startRadius = joint.boneRadius * radiusScale;
|
||||||
|
if (joint.parentIndex != -1) {
|
||||||
|
start = extractTranslation(_jointStates[joint.parentIndex].transform);
|
||||||
|
startRadius = geometry.joints[joint.parentIndex].boneRadius * radiusScale;
|
||||||
|
}
|
||||||
|
// for now, use average of start and end radii
|
||||||
|
float capsuleDistance;
|
||||||
|
if (findRayCapsuleIntersection(relativeOrigin, direction, start, end,
|
||||||
|
(startRadius + endRadius) / 2.0f, capsuleDistance)) {
|
||||||
|
minDistance = qMin(minDistance, capsuleDistance);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (minDistance < FLT_MAX) {
|
||||||
|
distance = minDistance;
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
bool Model::findSpherePenetration(const glm::vec3& penetratorCenter, float penetratorRadius,
|
bool Model::findSpherePenetration(const glm::vec3& penetratorCenter, float penetratorRadius,
|
||||||
glm::vec3& penetration, float boneScale, int skipIndex) const {
|
glm::vec3& penetration, float boneScale, int skipIndex) const {
|
||||||
const glm::vec3 relativeCenter = penetratorCenter - _translation;
|
const glm::vec3 relativeCenter = penetratorCenter - _translation;
|
||||||
|
|
|
@ -125,6 +125,8 @@ public:
|
||||||
/// Returns the average color of all meshes in the geometry.
|
/// Returns the average color of all meshes in the geometry.
|
||||||
glm::vec4 computeAverageColor() const;
|
glm::vec4 computeAverageColor() const;
|
||||||
|
|
||||||
|
bool findRayIntersection(const glm::vec3& origin, const glm::vec3& direction, float& distance) const;
|
||||||
|
|
||||||
bool findSpherePenetration(const glm::vec3& penetratorCenter, float penetratorRadius,
|
bool findSpherePenetration(const glm::vec3& penetratorCenter, float penetratorRadius,
|
||||||
glm::vec3& penetration, float boneScale = 1.0f, int skipIndex = -1) const;
|
glm::vec3& penetration, float boneScale = 1.0f, int skipIndex = -1) const;
|
||||||
|
|
||||||
|
|
|
@ -154,6 +154,44 @@ glm::vec3 addPenetrations(const glm::vec3& currentPenetration, const glm::vec3&
|
||||||
newPenetration - (currentDirection * directionalComponent);
|
newPenetration - (currentDirection * directionalComponent);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
bool findRaySphereIntersection(const glm::vec3& origin, const glm::vec3& direction,
|
||||||
|
const glm::vec3& center, float radius, float& distance) {
|
||||||
|
glm::vec3 relativeOrigin = origin - center;
|
||||||
|
float b = glm::dot(direction, relativeOrigin);
|
||||||
|
float c = glm::dot(relativeOrigin, relativeOrigin) - radius * radius;
|
||||||
|
if (c < 0.0f) {
|
||||||
|
distance = 0.0f;
|
||||||
|
return true; // starts inside the sphere
|
||||||
|
}
|
||||||
|
float radicand = b * b - c;
|
||||||
|
if (radicand < 0.0f) {
|
||||||
|
return false; // doesn't hit the sphere
|
||||||
|
}
|
||||||
|
float t = -b - sqrtf(radicand);
|
||||||
|
if (t < 0.0f) {
|
||||||
|
return false; // doesn't hit the sphere
|
||||||
|
}
|
||||||
|
distance = t;
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool findRayCapsuleIntersection(const glm::vec3& origin, const glm::vec3& direction,
|
||||||
|
const glm::vec3& start, const glm::vec3& end, float radius, float& distance) {
|
||||||
|
float minDistance = FLT_MAX;
|
||||||
|
float sphereDistance;
|
||||||
|
if (findRaySphereIntersection(origin, direction, start, radius, sphereDistance)) {
|
||||||
|
minDistance = qMin(minDistance, sphereDistance);
|
||||||
|
}
|
||||||
|
if (findRaySphereIntersection(origin, direction, end, radius, sphereDistance)) {
|
||||||
|
minDistance = qMin(minDistance, sphereDistance);
|
||||||
|
}
|
||||||
|
if (minDistance < FLT_MAX) {
|
||||||
|
distance = minDistance;
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
// Do line segments (r1p1.x, r1p1.y)--(r1p2.x, r1p2.y) and (r2p1.x, r2p1.y)--(r2p2.x, r2p2.y) intersect?
|
// Do line segments (r1p1.x, r1p1.y)--(r1p2.x, r1p2.y) and (r2p1.x, r2p1.y)--(r2p2.x, r2p2.y) intersect?
|
||||||
// from: http://ptspts.blogspot.com/2010/06/how-to-determine-if-two-line-segments.html
|
// from: http://ptspts.blogspot.com/2010/06/how-to-determine-if-two-line-segments.html
|
||||||
bool doLineSegmentsIntersect(glm::vec2 r1p1, glm::vec2 r1p2, glm::vec2 r2p1, glm::vec2 r2p2) {
|
bool doLineSegmentsIntersect(glm::vec2 r1p1, glm::vec2 r1p2, glm::vec2 r2p1, glm::vec2 r2p2) {
|
||||||
|
|
|
@ -49,6 +49,12 @@ bool findCapsulePlanePenetration(const glm::vec3& penetratorStart, const glm::ve
|
||||||
|
|
||||||
glm::vec3 addPenetrations(const glm::vec3& currentPenetration, const glm::vec3& newPenetration);
|
glm::vec3 addPenetrations(const glm::vec3& currentPenetration, const glm::vec3& newPenetration);
|
||||||
|
|
||||||
|
bool findRaySphereIntersection(const glm::vec3& origin, const glm::vec3& direction,
|
||||||
|
const glm::vec3& center, float radius, float& distance);
|
||||||
|
|
||||||
|
bool findRayCapsuleIntersection(const glm::vec3& origin, const glm::vec3& direction,
|
||||||
|
const glm::vec3& start, const glm::vec3& end, float radius, float& distance);
|
||||||
|
|
||||||
bool doLineSegmentsIntersect(glm::vec2 r1p1, glm::vec2 r1p2, glm::vec2 r2p1, glm::vec2 r2p2);
|
bool doLineSegmentsIntersect(glm::vec2 r1p1, glm::vec2 r1p2, glm::vec2 r2p1, glm::vec2 r2p2);
|
||||||
bool isOnSegment(float xi, float yi, float xj, float yj, float xk, float yk);
|
bool isOnSegment(float xi, float yi, float xj, float yj, float xk, float yk);
|
||||||
int computeDirection(float xi, float yi, float xj, float yj, float xk, float yk);
|
int computeDirection(float xi, float yi, float xj, float yj, float xk, float yk);
|
||||||
|
|
Loading…
Reference in a new issue