Что такое математика для перевода плоскости, вращая круг, имитирующий вращение колеса реального мира на земле? - PullRequest
0 голосов
/ 24 сентября 2018

Это как большой секрет в интернете.

Во всех играх я могу обнаружить, что колесо вращается медленнее или быстрее, чем должно быть относительно движения по земле.

Учитывая radius of the circle и угол intersection point with the plane at 90 deg translate the ground on X axis для имитацииРеальный мир катит колесо по земле.

В приведенном ниже примере наведите курсор мыши на круг, чтобы повернуть его.Земной сильфон должен двигаться так, как вы ожидаете в реальном мире.

const plane = $('#plane')
const planeX = plane.offset().left
const wheel = $('#wheel>div')
const radius = wheel.width() / 2
let degrees = 0
const offset = wheel.parent().offset()
$(document).on('mouseenter', '.interactive', event => {
  $('.interactive').css('background', 'rgba(172, 255, 47, 0.25)')
  const radians = Math.atan2(
    event.pageX - (offset.left + radius),
    event.pageY - (offset.top + radius)
  )
  const degreeWheelOffset = radians * (180 / Math.PI) * -1 - degrees // to start from where left off
  $(document).on('mousemove', event2 => {
    const radians = Math.atan2(
      event2.pageX - (offset.left + radius),
      event2.pageY - (offset.top + radius)
    )
    degrees = radians * (180 / Math.PI) * -1 - degreeWheelOffset
    wheel.css('transform', 'rotate(' + degrees + 'deg)').data('degree', degrees)
    plane.css('left', planeX - (Math.sin(radians) * radius) + 'px')
  })
})
$(document).on('mouseleave', '.interactive', () => {
  $('.interactive').css('background', '')
  $(document).off('mousemove')
})
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<div id="wheel" style="position:fixed;bottom:1em;left:50%;transform:translateX(-50%);">
    <div style="width:150px;height:150px;border:1px solid;border-radius:50%;background:url('data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAACMAAAAjCAAAAAA7suyFAAAABGdBTUEAALGPC/xhBQAAACBjSFJNAAB6JgAAgIQAAPoAAACA6AAAdTAAAOpgAAA6mAAAF3CculE8AAAAAmJLR0QA/4ePzL8AAAFuSURBVDjLfdRBa8IwGMbxx7cjEklIiVQqjsoCnvb9P8FACBQKngQHXpTJhJx2mRDZoXUmqfW9WX68f5tAR1tEw3jD5/EjUPKT1e/68NRQvil/X1MUGSbXeno9LRMUGmJ1NbsgSxHFIXEBeoiSENBHlITayc4hojTUTbiJbiGrulC36WT+UWuI28U82BIjakNNlccEwPGWIwCUWy16BNm520QAk+tydsWD6f44gUSzmF6AYUSU11oNkO6cRl92cAsA+PLgX+ybfEKQHVacijOejZc/R1qJHXtChLDf5Iza0SDhvK4mBGf0ng0R3RRjEOCWeiCn1Ech27twS7V9kPOM2WqC7k6d0Xvqh1RTjnEzcEZ9JjkvxFpPcDdwRsdv5zmrK4nQwBkV5jxXmzYUGDij7kfghbBdKDRw5v52nNWlRN/cD9MztSkneGTgjNoxwAtV64DE34T27gSzhcSQgTNqz1kUAjBKvmN6h4uQ8bM/WtmCgAk7YV0AAAAASUVORK5CYII=')">
      <div class="interactive" style="border-radius:50%;position:absolute;top:0;left:0;bottom:0;right:0"></div>
      <div style="position: absolute;top:50%;bottom:0;left:50%;border-left:1px solid;"></div>
    </div>
 </div>
 <div id="plane" style="position:fixed;bottom:0;left:-100vw;width:300vw;height:1em;border:1px solid;display:flex;justify-content:space-around;background:url('data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAACMAAAAjCAAAAAA7suyFAAAABGdBTUEAALGPC/xhBQAAACBjSFJNAAB6JgAAgIQAAPoAAACA6AAAdTAAAOpgAAA6mAAAF3CculE8AAAAAmJLR0QA/4ePzL8AAAFuSURBVDjLfdRBa8IwGMbxx7cjEklIiVQqjsoCnvb9P8FACBQKngQHXpTJhJx2mRDZoXUmqfW9WX68f5tAR1tEw3jD5/EjUPKT1e/68NRQvil/X1MUGSbXeno9LRMUGmJ1NbsgSxHFIXEBeoiSENBHlITayc4hojTUTbiJbiGrulC36WT+UWuI28U82BIjakNNlccEwPGWIwCUWy16BNm520QAk+tydsWD6f44gUSzmF6AYUSU11oNkO6cRl92cAsA+PLgX+ybfEKQHVacijOejZc/R1qJHXtChLDf5Iza0SDhvK4mBGf0ng0R3RRjEOCWeiCn1Ech27twS7V9kPOM2WqC7k6d0Xvqh1RTjnEzcEZ9JjkvxFpPcDdwRsdv5zmrK4nQwBkV5jxXmzYUGDij7kfghbBdKDRw5v52nNWlRN/cD9MztSkneGTgjNoxwAtV64DE34T27gSzhcSQgTNqz1kUAjBKvmN6h4uQ8bM/WtmCgAk7YV0AAAAASUVORK5CYII=')"><b>1</b><b>2</b><b>3</b><b>4</b><b>5</b><b>6</b><b>7</b><b>8</b><b>9</b></div>

Ответы [ 2 ]

0 голосов
/ 24 сентября 2018

Простой ответ

Для каждого вызова mousemove:

  • Вычислить изменение координаты мыши из предыдущего вызова
  • Рассчитать со знаком изменение угла, которое вызывает это движение мыши
  • Добавьте это к глобальному накопленному углу
  • Рассчитайте горизонтальный перевод = (глобальный угол в радианах) * (радиус колеса)

Изменение угла со знаком задается как перекрестное произведение между векторами на диаграмме ниже:

enter image description here

enter image description here

Лучше использовать atan2 для числовой устойчивости вблизи точек 90 градусов:

enter image description here

(Я уверен, что по крайней мере один из известных гуру геометрии здесь - например, Ив Дауст - имеет пост, объясняющий, как работает выше, поэтому я не буду делать это здесь.)

Рабочий код:

const plane = $('#plane')
const planeX = plane.offset().left
const wheel = $('#wheel>div')
const radius = wheel.width() / 2
const offset = wheel.parent().offset()

let degrees = 0;
$(document).on('mouseenter', '.interactive', event => {
  $('.interactive').css('background', 'rgba(172, 255, 47, 0.25)')
  let mouseX1 = event.pageX, mouseY1 = event.pageY;
  $(document).on('mousemove', event2 => {
    const mouseX2 = event2.pageX, mouseY2 = event2.pageY;

    // center position
    const centerX = offset.left + radius, 
          centerY = offset.top + radius;

    // vectors A - C and B - C
    const deltaX1 = mouseX1 - centerX, deltaY1 = mouseY1 - centerY;
    const deltaX2 = mouseX2 - centerX, deltaY2 = mouseY2 - centerY;

    // change in angle formula
    const deltaA = Math.atan2(deltaX1 * deltaY2 - deltaY1 * deltaX2,
                              deltaX1 * deltaX2 + deltaY1 * deltaY2);
  
    // increment
    degrees += deltaA * (180 / Math.PI);
    const radians = degrees * (Math.PI / 180);

    // set previous coordinates
    mouseX1 = mouseX2; mouseY1 = mouseY2;

    // apply
    wheel.css('transform', 'rotate(' + degrees + 'deg)').data('degree', degrees)
    plane.css('left', planeX - radians * radius + 'px') // simpler formula
  })
})
$(document).on('mouseleave', '.interactive', () => {
  $('.interactive').css('background', '')
  $(document).off('mousemove')
})
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<div id="wheel" style="position:fixed;bottom:1em;left:50%;transform:translateX(-50%);">
    <div style="width:150px;height:150px;border:1px solid;border-radius:50%;background:url('data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAACMAAAAjCAAAAAA7suyFAAAABGdBTUEAALGPC/xhBQAAACBjSFJNAAB6JgAAgIQAAPoAAACA6AAAdTAAAOpgAAA6mAAAF3CculE8AAAAAmJLR0QA/4ePzL8AAAFuSURBVDjLfdRBa8IwGMbxx7cjEklIiVQqjsoCnvb9P8FACBQKngQHXpTJhJx2mRDZoXUmqfW9WX68f5tAR1tEw3jD5/EjUPKT1e/68NRQvil/X1MUGSbXeno9LRMUGmJ1NbsgSxHFIXEBeoiSENBHlITayc4hojTUTbiJbiGrulC36WT+UWuI28U82BIjakNNlccEwPGWIwCUWy16BNm520QAk+tydsWD6f44gUSzmF6AYUSU11oNkO6cRl92cAsA+PLgX+ybfEKQHVacijOejZc/R1qJHXtChLDf5Iza0SDhvK4mBGf0ng0R3RRjEOCWeiCn1Ech27twS7V9kPOM2WqC7k6d0Xvqh1RTjnEzcEZ9JjkvxFpPcDdwRsdv5zmrK4nQwBkV5jxXmzYUGDij7kfghbBdKDRw5v52nNWlRN/cD9MztSkneGTgjNoxwAtV64DE34T27gSzhcSQgTNqz1kUAjBKvmN6h4uQ8bM/WtmCgAk7YV0AAAAASUVORK5CYII=')">
      <div class="interactive" style="border-radius:50%;position:absolute;top:0;left:0;bottom:0;right:0"></div>
      <div style="position: absolute;top:50%;bottom:0;left:50%;border-left:1px solid;"></div>
    </div>
 </div>
 <div id="plane" style="position:fixed;bottom:0;left:-100vw;width:300vw;height:1em;border:1px solid;display:flex;justify-content:space-around;background:url('data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAACMAAAAjCAAAAAA7suyFAAAABGdBTUEAALGPC/xhBQAAACBjSFJNAAB6JgAAgIQAAPoAAACA6AAAdTAAAOpgAAA6mAAAF3CculE8AAAAAmJLR0QA/4ePzL8AAAFuSURBVDjLfdRBa8IwGMbxx7cjEklIiVQqjsoCnvb9P8FACBQKngQHXpTJhJx2mRDZoXUmqfW9WX68f5tAR1tEw3jD5/EjUPKT1e/68NRQvil/X1MUGSbXeno9LRMUGmJ1NbsgSxHFIXEBeoiSENBHlITayc4hojTUTbiJbiGrulC36WT+UWuI28U82BIjakNNlccEwPGWIwCUWy16BNm520QAk+tydsWD6f44gUSzmF6AYUSU11oNkO6cRl92cAsA+PLgX+ybfEKQHVacijOejZc/R1qJHXtChLDf5Iza0SDhvK4mBGf0ng0R3RRjEOCWeiCn1Ech27twS7V9kPOM2WqC7k6d0Xvqh1RTjnEzcEZ9JjkvxFpPcDdwRsdv5zmrK4nQwBkV5jxXmzYUGDij7kfghbBdKDRw5v52nNWlRN/cD9MztSkneGTgjNoxwAtV64DE34T27gSzhcSQgTNqz1kUAjBKvmN6h4uQ8bM/WtmCgAk7YV0AAAAASUVORK5CYII=')"><b>1</b><b>2</b><b>3</b><b>4</b><b>5</b><b>6</b><b>7</b><b>8</b><b>9</b></div>

Чуть более сложный ответ

Приведенный выше код дает приближение, что во время цикла опроса мыши (интервал между последовательными mousemove вызовами) колесо остается неподвижным.Для непрерывного движения это, конечно, неверно - центр колеса постоянно движется вместе с мышью.

Отсюда вытекает нелинейное дифференциальное уравнение первого порядка , которое дает«физически правильный» угол дельты на движение мыши (здесь я не буду показывать вывод):

enter image description here

где m - положение мыши,p - это положение колеса, а theta - это накопленный угол.С некоторой подстановкой и перестановкой переменных это можно решить аналитически;в противном случае его можно легко интегрировать численно, например, с помощью адаптивного RK4.

... Но, конечно, если частота опроса достаточно высока (как это обычно бывает), то есть угол дельты за цикл опроса мал, тоаппроксимация более чем достаточно точна.

0 голосов
/ 24 сентября 2018

Когда транспортное средство продвигается на 2π м, колесо катится на 2π м, т.е. угол 2π / r радиан.

Когда транспортное средство продвигается на dm, колесо катится dm, то есть угол d / r радиан.

...