2012-06-13 4 views
1

Я пытаюсь написать Java-программу для поддержки моделирования с ограниченным анализом с неравновесной диффузией. Базовый код для моделирования движущейся частицы находится на месте, пока указанная частица не ударит по статической центральной частице. В этот момент я стараюсь, чтобы движущаяся частица просто касалась статической. Однако по неизвестным причинам он иногда терпит неудачу (первые 2 из 8 частиц пересекаются, остальные 6 - прекрасны).Круг для столкновения круга

Вот код:

boolean killed, collide; 
    double xp, yp, dx, dy, theta, xpp, ypp, length; 

    int xc = 200; 
    int yc = 200; 
    int killRadius = 200; 
    int releaseRadius = 150; 
    int partRadius = 14; 
    int partDiam = 2 * partRadius; 

    drawCircle(xc, yc, killRadius); // kill 
    drawCircle(xc, yc, releaseRadius); // release 
    drawCircle(xc, yc, partRadius); // center particle 

    //while (true) { 
     killed = false; 
     collide = false; 

     theta = Math.random() * Math.PI * 2; 
     xp = xc + releaseRadius * Math.cos(theta); 
     yp = yc + releaseRadius * Math.sin(theta); 

     while (true) { 

      theta = Math.random() * Math.PI * 2; 
      length = partDiam; 

      xpp = xp; 
      ypp = yp; 

      xp = xp + length * Math.cos(theta); 
      yp = yp + length * Math.sin(theta); 

      //drawCircle((int) xp, (int) yp, partRadius); 

      // Should it be killed ? (maybe could use a box to fasten 
      // computations... 
      // Would switching the test for kill w test for collision 
      // improve perf ? 
      dx = xp - xc; 
      dy = yp - yc; 
      if ((dx * dx) + (dy * dy) > killRadius * killRadius) { 
       killed = true; 
       break; 
      } 

      // Does it collide with center? replace by any particle... 
      dx = xp - xc; 
      dy = yp - yc; 
      if ((dx * dx) + (dy * dy) < (partDiam) * (partDiam)) { 
       collide = true; 
       break; 
      } 
     } 
// Probably something is wrong here... 
     if (collide) { 
      // no absolute value because particles move at most by diameter 
      double depthPenetration = partDiam 
        - Math.sqrt((dx * dx) + (dy * dy)); 
      dx = xpp - xp; 
      dy = ypp - yp; 
      // shorten distance travelled by penetration length to ensure 
      // that 
      // particle is tangeant 
      length = Math.sqrt((dx * dx) + (dy * dy)) - depthPenetration; 
      xp = xpp + length * Math.cos(theta); 
      yp = ypp + length * Math.sin(theta); 
      drawCircle((int) xp, (int) yp, partRadius); 
     } 
    //} 

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

+2

Слишком много кода для отладки. Начнем с того, какой результат вы получаете и чего вы ожидаете? – djechlin

+0

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

+0

Должен ли я признать, что мне все еще сложно понять, что вы пытаетесь сделать гораздо меньше, чем вопрос о том, что вы хотите исправлять? Каковы проблематичные симптомы, что вы ожидаете, и что вы получаете? – trumpetlicks

ответ

0

Я не думаю, что могу отлаживать ваш код, но несколько лет назад (более десяти лет назад) я написал несколько java.awt.Shape основанных на столкновении процедур, которые могут помочь ... проверить ShapeUtils.java из этого :

http://www.cs101.org/psets/breakout/solns/breakout-src.jar

Одним из самых вероятных проблем, вы можете иметь то, что ява круги сплайн кривые с 4-х точках, и, таким образом, если вы убедитесь, что все точки, определяющие круг внутри другой формы, вы будете по-прежнему пропустите случай, когда кривая сплайна выгибается в другую форму, но ни одна из точек не находится внутри объекта. Мое решение (которое не может быть достаточно хороши для вашего дела было не переделать форму, пока расстояние между точками вдоль их соответствующих краев было меньше наибольшая допустимая ошибка:

/** 
    * Convert any AWT shape into a shape with a specified precision. 
    * The specified precision indicates the maximum tolerable distance 
    * between knot points. If the shape is already precise enough then 
    * it is returned unmodified. 
    * 
    * @param aShape the shape to be converted if necessary. 
    * @param precision the maximum tolerable distance between knot points. 
    * @return A more precise version of the shape, or the same shape if 
    *   the precision is already satisfied. 
    */ 
    public static Shape getPreciseShape(Shape aShape, float precision) { 

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

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

Редактировать: Позвольте мне подвести итог моему предложению ... в повторном чтении Я понимаю, что я заблудился в деталях и никогда не могу указать ключевую концепцию ... Java имеет множество подпрограмм, которые хорошо работают для тестирование различных реализаций Shape (включая круги). Мое предложение - использовать библиотеки java как можно больше, и получить результаты, которые вы можете проверить, верны. После того, как у вас есть рабочий код и методика проверки работы кода, если вам требуется больше скорости, начните оптимизировать его части, предпочтительно после профилирования запущенной программы (которая дает правильные результаты), чтобы увидеть, какие части ограничивают вашу производительность.

1

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

Позвольте мне упомянуть одну вещь в начале: Это возрождение сфагетти-монстра, не так ли? Вам нравятся глобальные переменные? Длинные, суперпотентные давайте сделаем все прямо сейчас и здесь methoods?

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

Если ваши переменные не меняются: сделайте их окончательными. Это упрощает рассуждение о них.final int killRadius = 200; означает, что получить информацию о типе вместе со значением и, надеюсь, незадолго до первого использования, и что он никогда не будет изменен. Конфигурация только в исходном коде. Наверное, не слишком сложный кандидат. В отличие от двойного йх - не инициализируется, потому что получить инициализируется внутри цикла,

static void foo() { 

    final int xc = 200; 
    final int yc = 200; 
    final int killRadius = 200; 
    final int releaseRadius = 150; 
    final int partRadius = 14; 

    drawCircle (xc, yc, killRadius); // kill 
    drawCircle (xc, yc, releaseRadius); // release 
    drawCircle (xc, yc, partRadius); // center particle 

    //while (true) { 
    boolean killed = false; 
    boolean collide = false; 

    double theta = Math.random() * Math.PI * 2;  
    double xp = xc + releaseRadius * Math.cos (theta); 
    double yp = yc + releaseRadius * Math.sin (theta); 
    double dx, dy, xpp, ypp; 

    while (true) { 

     theta = Math.random() * Math.PI * 2; 
     final int partDiam = 2 * partRadius; 
     final double length = partDiam; 

     xpp = xp; 
     ypp = yp; 

     xp += length * Math.cos (theta); 
     yp += length * Math.sin (theta); 

     dx = xp - xc; 
     dy = yp - yc; 
     if ((dx * dx) + (dy * dy) > killRadius * killRadius) { 
      killed = true; 
      break; 
     } 

     // Why again assign dx = xp -xc? Did any of these values change meanwhile? 
     // I don't think so. 
     // dx = xp - xc; 
     // dy = yp - yc; 
     if ((dx * dx) + (dy * dy) < (partDiam) * (partDiam)) { 
      collide = true; 
      break; 
     } 
    } 
    if (collide) { 
     // no absolute value because particles move at most by diameter 
     double depthPenetration = partDiam - Math.sqrt((dx * dx) + (dy * dy)); 
     dx = xpp - xp; 
     dy = ypp - yp; 
     // shorten distance travelled by penetration length to ensure 
     // that 
     // particle is tangeant 
     final double length = Math.sqrt((dx * dx) + (dy * dy)) - depthPenetration; 
     xp = xpp + length * Math.cos (theta); 
     yp = ypp + length * Math.sin (theta); 
     drawCircle ((int) xp, (int) yp, partRadius); 
    } 

Если вы структурировать свой код, как это, вы не только видите, что некоторое значение, как Хс 200 и никогда не изменял - в глава цикла while вы видите, что theta не объявляется внутри цикла, поэтому либо он используется позже вне цикла, либо он последовательно изменяется внутри цикла. Сделать x + = 4; вы не можете инициализировать x во время прохождения цикла.

В конце большого времени, у вас есть два одинаковых блоки:

dx = xp - xc; 
    dy = yp - yc; 
    if ((dx * dx) + (dy * dy) (OP) a OP b) { 
     c = true; 
     break; 
    } 

но хры, хс и де не изменились между тем - ни у-эквивалентами. Это ошибка, или почему вы назначаете их снова?

Затем вы можете избавиться от своего бесконечного, пока этот способ: поскольку оба условия завершают время, поместите условия во время теста и вызовите второй блок (без повторения задания), только если первый из них был недействительным, т вводится - ключевое слово, чтобы сделать это else:

while (!killed && !collide) { 

     // ... 

     dx = xp - xc; 
     dy = yp - yc; 
     if ((dx * dx) + (dy * dy) > killRadius * killRadius) { 
      killed = true; 
     } 
     else if ((dx * dx) + (dy * dy) < (partDiam) * (partDiam)) { 
      collide = true; 
     } 
    } 

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

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