2016-12-16 14 views
0

Мне нужно равномерно распределить кучу выровненных по оси скользящих прямоугольников, ограниченных максимальной шириной/высотой и некоторыми горизонтальными/вертикальными координатами в зависимости от положения самих скользящих фигур. Прямоугольники ограничены в одном направлении, могут скользить вдоль другой оси, не могут пересекаться и не перешагиваться.Принудительная компоновка для прямоугольных прямоугольных форм

Этот вопрос основан на: How to implement a constraint solver for 2-D geometry? и хорошо принятом предложении Спектра для принудительного решения с принудительным управлением.

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

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

Соответствующий код в функции Solver.solve() ниже, где Sz представляют собой, соответственно, высоту формы для горизонтальных, а ширина для вертикальных:

for(var i=0, l=sliders.length; i<l; i++) { 
    var si = sliders[i]; 
    for(var j=i+1, k=sliders.length; j<k; j++) { 
     var sj = sliders[j]; 
     if(si._horizontal == sj._horizontal) { 
      // longer side interaction 
      if(si._horizontal == 1) { 
       a0 = si.X + si.a; a1 = sj.X + sj.a; 
       b0 = si.X + si.b; b1 = sj.X + sj.b; 
       x0 = si.Y; x1 = sj.Y; 
      } else { 
       a0 = si.Y + si.a; a1 = sj.Y + sj.a; 
       b0 = si.Y + si.b; b1 = sj.Y + sj.b; 
       x0 = si.X; x1 = sj.X; 
      } 
      if(((a0 <= b1) && (b0 >= a1)) || ((a1 <= b0) && (b1 >= a0))) { 
       x0 = x1 - x0; 
       if((si.ia >= 0) && (x0 < 0.0) && ((fabs(si.x0) < si.Z) || (fabs(si.x0) > fabs(x0)))) si.x0 = -x0; 
       if((si.ia >= 0) && (x0 > 0.0) && ((fabs(si.x1) < si.Z) || (fabs(si.x1) > fabs(x0)))) si.x1 = -x0; 
       if((sj.ia >= 0) && (x0 < 0.0) && ((fabs(sj.x0) < sj.Z) || (fabs(sj.x0) > fabs(x0)))) sj.x0 = +x0; 
       if((sj.ia >= 0) && (x0 > 0.0) && ((fabs(sj.x1) < sj.Z) || (fabs(sj.x1) > fabs(x0)))) sj.x1 = +x0; 
      } 
      // shorter side interaction 
      if(si._horizontal == 1) { 
       a0 = si.Y - si.Z; a1 = sj.Y + sj.Z; 
       b0 = si.Y + si.Z; b1 = sj.Y + sj.Z; 
       x0 = si.X; x1 = sj.X; 
      } else { 
       a0 = si.X - si.Z; a1 = sj.X + sj.Z; 
       b0 = si.X + si.Z; b1 = sj.X + sj.Z; 
       x0 = si.Y; x1 = sj.Y; 
      } 
      if(((a0 <= b1) && (b0 >= a1)) || ((a1 <= b0) && (b1 >= a0))) { 
       if(x0 < x1) { 
        x0 += si.b; x1 += sj.a; 
       } else{ 
        x0 += si.a; x1 += sj.b; 
       } 
       x0 = x1 - x0; 
       if(si.ia >= 0) { 
        var sa = this.sliders[si.ia]; 
        if((sa.ia >= 0) && (x0 < 0.0) && ((fabs(sa.x0) < sa.Z) || (fabs(sa.x0) > fabs(x0)))) sa.x0 = -x0; 
        if((sa.ia >= 0) && (x0 > 0.0) && ((fabs(sa.x1) < sa.Z) || (fabs(sa.x1) > fabs(x0)))) sa.x1 = -x0; 
       } 
       if(sj.ia >= 0) { 
        var sa = sliders[sj.ia]; 
        if((sa.ia >= 0) && (x0 < 0.0) && ((fabs(sa.x0) < sa.Z) || (fabs(sa.x0) > fabs(x0)))) sa.x0 = +x0; 
        if((sa.ia >= 0) && (x0 > 0.0) && ((fabs(sa.x1) < sa.Z) || (fabs(sa.x1) > fabs(x0)))) sa.x1 = +x0; 
       } 
      } 
     } 
    } 
} 
// set x0 as 1D vector to closest perpendicular neighbour before and x1 after 
for(var i=0, l=sliders.length; i<l; i++) { 
    var si = sliders[i]; 
    for(var j=i+1, k=sliders.length; j<k; j++) { 
     var sj = sliders[j]; 
     if(si._horizontal != sj._horizontal) { 
      // skip ignored sliders for this 
      var ignore = false; 
      for(var n=0, m=si.ic.length; n<m; n++) { 
       if(si.ic[n] == j) { 
        ignore = true; 
        break; 
       } 
      } 
      if(ignore === true) continue; 
      if(si._horizontal == 1) { 
       a0 = si.X + si.a; a1 = sj.X - sj.Z; 
       b0 = si.X + si.b; b1 = sj.X + sj.Z; 
       x0 = si.Y; 
      } else { 
       a0 = si.Y + si.a; a1 = sj.Y - sj.Z; 
       b0 = si.Y + si.b; b1 = sj.Y + sj.Z; 
       x0 = si.X; 
      } 
      if(((a0 <= b1) && (b0 >= a1)) || ((a1 <= b0) && (b1 >= a0))){ 
       if(si._horizontal == 1) { 
        a1 = sj.Y + sj.a; 
        b1 = sj.Y + sj.b; 
         } else { 
        a1 = sj.X + sj.a; 
        b1 = sj.X + sj.b; 
       } 
       a1 -= x0; b1 -= x0; 
       if(fabs(a1) < fabs(b1)) x0 = -a1; else x0 = -b1; 
       if((si.ia >= 0) && (x0 < 0.0) && ((fabs(si.x0) < si.Z) || (fabs(si.x0) > fabs(x0)))) si.x0 = +x0; 
       if((si.ia >= 0) && (x0 > 0.0) && ((fabs(si.x1) < si.Z) || (fabs(si.x1) > fabs(x0)))) si.x1 = +x0; 
       if(sj.ia < 0) continue; 
       var sa = sliders[sj.ia]; 
       if((sa.ia >= 0) && (x0 < 0.0) && ((fabs(sa.x0) < sa.Z) || (fabs(sa.x0) > fabs(x0)))) sa.x0 = -x0; 
       if((sa.ia >= 0) && (x0 > 0.0) && ((fabs(sa.x1) < sa.Z) || (fabs(sa.x1) > fabs(x0)))) sa.x1 = -x0; 
      } 
     } 
    } 
} 

Как должно быть вычисление силы для прямоугольных форм, чтобы получить от силового поля равномерное распределение, т. е. такое расстояние между прямоугольниками будет максимально возможным? Подумайте, что прямоугольники действительно горячие и должны быть максимально расставлены по отношению к своим пользовательским ограничениям x/y.

Любая помощь будет принята с благодарностью.

EDIT:

Пример: https://plnkr.co/edit/3xGmAKsly2qCGMp3fPrJ?p=preview

ответ

1

Если я получаю этот вопрос прямо OP запрашивает набор правил вождения ползунки поэтому окончательное состояние моделирования, приводящие к правильному решению.

Так вот мой подход это действительно перепросмотр моего решателя кода из связанного ответа в OP, но это не будет вписываться в там, как я уже достиг предела 30 МБайт, и я чувствую, что нужно немного больше объяснить то просто прокомментировал код так вот:

  1. сила

    для обеспечения равного расстояния как можно больше вы должны изменить правила немного (помимо реальной физики), так что вы учет только ближайшим препятствие для вождения Force instea d из всех них, как в реальном мире. Также сила воздействует только на расстояние и не взвешивается также по площади контакта/перекрытия, так как большинство физических сил (включая электростатические).

    Так что во время итерации i-th слайдера (желтых) найти расстояние до ближайшего препятствия во всех 4-х направлениях (красного):

    closest neighbors

    И вычислить движущую силу, которая должна быть масштабируются с расстоянием. На самом деле не имеет значения, линейно или нет, но для равномерно распределенных препятствий слева/справа или вверх/вниз должна быть полученная сила равна нулю. Масштабирование изменяет в основном поведение динамики.Конечный результат зависит от него только в состояниях, где ограничения блокируют движение для достижения равномерного интервала. Таким образом, вы можете использовать, например, любой из них:

    F = c * (d1-d0) 
    F = c * (d1^2 - d0^2) 
    F = c * (1/d1^2 - 1/d0^2) 
    

    Где c некоторый коэффициент величины и d0,d1 являются 2 ближайшими заградительные расстояния в одной и той же оси.

    Теперь от этого вы получите 2 силы (по одному на каждой оси)

    • Fx - горизонтальная ось силы
    • Fy - вертикальная ось сила

    В двух словах, что это его. Но проблема с ограничениями. Например, выбранный слайдер (желтый) является вертикальным. Это означает, что он может двигаться только по оси x. Таким образом, вы положили на него Fx. Сила Fy должна приводить в движение свой родительский ползунок (синий), который является горизонтальным и может перемещаться по оси y (если не фиксирован грубой).

    Это представляет проблему, потому что этот слайдер также может иметь свой собственный Fy, поэтому вы всегда должны выбирать только самую сильную силу с каждой стороны. Это означает, что вам нужно помнить оба расстояния/силы с каждой стороны и всегда выбирать наименьшее расстояние или | высшее | силы с каждой стороны.

    Вот откуда взялись переменные x0,x1, они удерживают минимальное расстояние в движущейся оси до ближайших препятствий (от включенного ребенка) и только после того, как вычисление всех ползунков преобразуется в Fx,Fy движущими силами.

    Для обнаружения соседей и столкновений Я понимаю, 3 тип взаимодействия

    • перпендикулярен, которая находится между горизонтальным и вертикальным ползунком (нижнее взаимодействием на изображении)
    • широкого параллельный, который находится между двумя слайдерами (левое, правое взаимодействие на изображении)
    • короткий параллельный, который находится между двумя ползунками sam е тип контакта с его коротких сторон (сверху взаимодействие на изображение)
  2. Пределы и коэффициенты

    Я также ввел некоторые ограничения скорости и коэффициенты (а не только для сброса, чтобы избежать колебаний). Пределы скорости и ускорения влияют на время и стабильность решения. Существует и другая причина использовать их (я не делаю), и это необходимо для сохранения порядка ползунков, чтобы они не пропускали друг друга. Это можно сделать, просто ограничивая максимальную скорость, поэтому на одну итерацию любой слайдер не будет перемещаться больше половины толщины ползунков. Таким образом, в случае столкновения столкновение подпишет.

    Я пропустил это в своем коде, потому что моя конфигурация установлена ​​так, что порядок слайдеров соответствует его номеру индекса. Поэтому, если я обнаруживаю, что какой-либо слайдер находится на левой стороне какого-либо тестируемого слайдера, в то время как его индекс выше, это означает, что он пропустил, и я обрабатываю его, вместо этого восстанавливая последнюю позицию ... Это дешевый хак и не будет работать в сложных наборах, где многие детские слайдеры в цепочке не одни.

  3. Обратной связь

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

+0

Hi Spektre, не могли бы вы помочь мне завершить этот проект? У меня много тестовых данных, с вашей помощью я мог бы это сделать вовремя. – deblocker

+0

@deblocker мое свободное время ограничено, что вам нужно? – Spektre

+0

@deblocker Есть еще несколько проблем: например, как определить решение действительно оптимально? Как предложила Нина, может быть какая-то весовая функция, которая будет отражать деформации интервала ... что-то вроде 1. получить соседние отношения. 2. вычислить максимальные и средние различия в интервалах в каждой строке/столбце. 3. решить решаемое или нерассмотренное состояние. Дело в том, что вам нужно указать формат ввода. Как я уже упоминал ранее, есть конфликты, так как некоторые слайдеры пересекаются уже так, как их обрабатывать (я игнорирую их для пересекающихся слайдеров, но правильно ли это?) – Spektre

 Смежные вопросы

  • Нет связанных вопросов^_^