Simulation info biologique / js

Fermé
LeToulousain - 31 mars 2020 à 11:44
 LeToulousain - 31 mars 2020 à 16:53
Bonjour,

J'ai besoin d'une ame charitable pour me conseiller !!
Alors voilà : j'ai un projet a faire, dans lequel je dois modélisation un processus biologique simplifié sur une page HTML, avec javascript, dans lequel au départ, , dans une membrane plasmique, toutes les molécules de neurotransmetteurs et de récepteurs fermés sont affichées à l’écran. Leur nombre et positions sont aléatoires, et les neurotransmetteur, lorsqu'il touche un recepteur, fusionne avec ce dernier pour former un autre type de recepteur. Jusque là, tout va bien. J'ai fais 2 objet : neurotransmetteur et recepteur.
Mais je dois également placer les recepteur (grace a une boucle while) sur chaque coté de la membrane (rec1 rec2 rec3 rec4) de manière a ce qu'il ne se chevauche pas, mais je ne vois absolument pas comment faire, j'ai essayé de rajouter 40 (longueur des recepteur) a chaque itération afin que la position augmente et donc qu'elle ne soit pas la même, mais cela n'a pas fonctionné.
Pourriez-vous me donner une piste/idée ??
Voici mon code :
// setup canvas
const canvas = document.querySelector('canvas');
const ctx = canvas.getContext('2d');
const width = canvas.width = window.innerWidth;
const height = canvas.height = window.innerHeight;
// function to generate random number
const mbh=200;
const mbw=400;
const mbx=120;
const mby=220;

//fonction qui dessine le contour de la membrane
function Membrane(){
    ctx.fillStyle = "black";
    ctx.fillText("Espace pré- synaptique", 10, 200); 
    ctx.fillText("Espace post- synaptique", 200, 350); 
    ctx.beginPath();
    ctx.lineWidth = "5";
    ctx.strokeStyle = "black";
    ctx.rect(mbx, mby, mbw, mbh);
    ctx.stroke();
}

//fonction qui renvoie un nombre random entre 2 valeurs
function random(min,max) {
   const num = Math.floor(Math.random()*(max-min)) + min;
   return num;
}

//classe des Recepteur
class Receptor {

  constructor(xr, yr,w,h,color,velXr,velYr){
    this.xr = xr;// x
    this.yr = yr;//y
    this.w = w;//longueur
    this.h = h;//largeur
    this.color=color;
    this.velX = 0;
    this.velY = 0;
  }

  update() {
    this.xr += this.velX;
    this.yr += this.velY;
 }

  //fonction qui dessine le recepteur
  drawR() {
    ctx.beginPath();
    ctx.rect(this.xr,this.yr,this.w,this.h);
    ctx.fillStyle = this.color;
    ctx.fill();
  }
}


class NeuroT {

  constructor(x, y, velX, velY, color, size) {
     this.x = x;
     this.y = y;
     this.velX = velX;
     this.velY = velY;
     this.color = color;
     this.size = size;
     this.switch = false;
     this.switchw = 0;
     this.switchh = 0;
  }

  draw() {
     ctx.beginPath();
     ctx.fillStyle = this.color;
     if(!this.switch)
        ctx.arc(this.x, this.y, this.size, 0, 2 * Math.PI);
     else
        ctx.rect(this.x, this.y, this.switchw, this.switchh);
     ctx.fill();
  }

  collide(receptors){
    for(var i = 0; i < receptors.length; i++){
      if((this.x > receptors[i].xr && this.x < (receptors[i].xr + receptors[i].w)) && (this.y > receptors[i].yr && this.y < (receptors[i].yr + receptors[i].h))){
          receptors[i].velX = this.velX;
          receptors[i].velY = this.velY;
          receptors[i].color = "green";
          this.size = 0;
      }
    }
  }
  update() {
    this.x += this.velX;
    this.y += this.velY;
 }


}

var receptors=[];
var neuros = [];
let neuro_number = random(20,30);
let receptors_number = random(12,18);


while (neuros.length < neuro_number) {
  let neuro = new NeuroT(
     (mbx+(mbx+mbw))/2,
     (mbh+(mbh+mbh))/2,
     random(-3,3),
     random(-3,3),
     "orange",
     10
  );

 neuros.push(neuro);
}

while(receptors.length<receptors_number){
  //on fait 4 types de recepteur pour chaque cote de la membrane
  let d = mbx - (40/2);
  let g = (mbx+mbw) - (40/2);
  let h = mby - (40/2);
  let b = (mby+mbh)-(40/2);
  let rec = new Receptor (
    random(d,g),
    h,
   40,40,
   "RoyalBlue",
   0,0
  );

  let rec1 = new Receptor (
    random(d,g),
    b,
    40,40,
    "RoyalBlue",
    0,0
   );
   let rec2 = new Receptor (
    d,
    random(h,b),
    40,40,
    "RoyalBlue",
    0,0
   );

   let rec3 = new Receptor (
    g,
    random(h,b),
    40,40,
    "RoyalBlue",
    0,0
   );

   h+=40;
   d+=40;
   b+=40;
   g+=40;


   
  receptors.push(rec);
  receptors.push(rec1);
  receptors.push(rec2);
  receptors.push(rec3);
}





function loop() {
  ctx.fillStyle = 'rgba(255, 255, 255, 0.25';
  ctx.fillRect(0, 0, width, height);
  Membrane();

  for (let i = 0; i < neuros.length; i++) {
    neuros[i].draw();
    neuros[i].update();
    neuros[i].collide(receptors);
  }
  for(let j=0; j<receptors.length;j++){
    receptors[j].drawR();
    receptors[j].update();
  }
  requestAnimationFrame(loop);
}

loop();


En esperant que vous puissiez m'aider !
Je vous remercie :)
A voir également:

4 réponses

Bonjour,
je ne suis pas sûr de comprendre votre problème ni l'énoncé.
Pour vous aider je vais tenter de les rapporter à la représentation sur le repère cartésien, ce qui peut-être erroné depuis le point de vue du modèle initial:

Ce que vous voulez faire et pose problème est que vous avez un rectangle qui doit afficher sur chacun de ses côtés un autre élément.
La question (que vous semblez posé et j'espère avoir bien compris) c'est comment dans le repère en 2 dimensions repérer chaque côté pour qu'il n'y ait qu'un seul élément pour chaque côté du polygone.
Votre solution est d'ajouter 40? Là j'ai du mal à suivre, 40 de quelle unité?

Pour répondre à la formulation que j'ai exprimée il faut repérer les droites qui composent les 4 côtés du rectangle et attribuer à chacune les positions x et y correspondantes.

Hors pour repérer 4 'faces' d'un rectangle le moyen mathématique est assez évident:
Ce sont les coordonnées exprimées et utilisées dans la modélisation du polygone telle:

x et y le plus petit en position dans le repère cartésien.
les vecteurs exprimés par longueur et hauteur déterminent tout les autres points donc les 4 'lignes' des côtés selon les droites exprimées par 2 points cartésiens:

côté base = (x , y) à (x+longueur, y)
côté gauche = (x,y) à (x,y+hauteur)
côté droit = (x+longueur , y) à (x+longueur, y +hauteur)
côté du dessus = (x, y +hauteur) à (x+longueur, y+hauteur)

Pour ajouter une forme adjacente dans notre repère cartésien à l'une des faces il faut donc que les dimensions de les positions de la forme à rajoutée ait un côté adjacent tenant compte des chevauchements éventuels ou de l'inclusion à l'intérieur:
Nous en venons à :
Pour chaque côté rajouter un élément exprimée par les 4 points de ses coordonnées(pour simplifier je leur attribue une forme rectangle aussi il faut donc d'autres calculs si la forme est différente ben entendu) tels:
'j'utiliserais ici comme point de référence le milieu des droites qui bien sûr doit être changé si on veut utiliser un côté ou l'autre ou une valeur aléatoire le long des droites de chaque côté.)

récepteur les 4 coordonnées ont une face en commun telle pour le côté base nommée (rx(n), ry(n)) n étant un numéro arbitraire des 4 coordoonnées du points du récepteur soit point 1 = (rx0, ry0) etc...

(rx0,ry0) à (rx1 , ry1) sont les coordonnées du côté adjacent
et s'expriment comme cela pour le côté base dont on a obtenu les coords. plus haut:

abscisse du premier point
rx0 = x - longueur/2 - (longueur_du_récepteur/2)
x-longueur/2 étant le milieu et notre point de référence.
longueur_du_récepteur/2 est la moitié de la longueur du récepteur.

ordonnée du premier point
ry0 = y-hauteur/2 - hauteur_du_récepteur/2


A partir d'un seul point et connaissant les dimensions il est aisé de déduire les autres coordonnées.
Utiliser + ou - pour les autres côtés selon que la forme doit être inscrite ou 'externe' aux 4 côtés du rectangle auquel ajouter ceux des récepteurs.

J'espère que ça peut correspondre et vous aider. Pour vous aider à définir l'algorithme nécessairevous pouvez dessiner les rectangles sur une feuille de papier mais pour l'essentiel ce ne sont que des déductions tenant compte ou non des collisions des objets dans le repère(le chevauchement ou non) qui vont servir de limite et de fixer des points de références correspondant à des lignes qui se chevauchent et exprimant leur liaison avec chaque côté du rectangle qui doit avoir d'autres objets adjacents.

Enfin c'est plus facile à comprendre que d'en parler je pense ;)
0
Merci pour votre réponse !! Il est vrai que je n'ai pas été très clair, j'ai bel et bien réussi a placer mes récepteurs, il peut en fait en avoir plusieurs sur un même coté (je génère aléatoirement entre 12 et 18 récepteur en tout). Mon problème est que comme il s'agit d'un placement aléatoire, certains récepteurs se chevauchent..
Voici un schéma qui j'espère vous éclairera, qui représente un coté de la membrane, avec ses récepteurs :
-----| | |--------| |------ ici les 2 premiers récepteurs se chevauchent
--------| |--------| |-----------| |-------- et voici mon modèle "idéal"

En espérant me faire comprendre

Je vous remercie pour l'aide apportée
0
Ah je voulais en parler du chevauchement mais n'avais pas tout compris de la question.
Pour éviter le chevauchement il faut que chaque ajout teste si il y a chevauchement (ça s'appelle un texte de collision):

Donc à chaque ajout(sauf le premier) il faut une boucle qui compare la nouvelle position et les distances longueur/largeurs avec celles existantes.
=> Si pas de collision d'éléments on fait l'ajout et passe au suivant
=> sinon on recommence à attribuer une valeur aléatoire et nouveau test, bien sûr ce sera plus rapide si il y a moins
de risque de collision(donc un espace assez large par rapport aux dimensions de l'élément à ajouter).

Il serais même plus logique d'avant d'ajouter de générer toutes les positions en tenant compte de ça (la collision)plutôt que d'attendre de le faire au moment d'afficher.

Je fais un exemple simplifié du test de collision et je publie ça.
0
LeToulousain
31 mars 2020 à 16:22
Oui, la collision me paraissait bien a premier abord (c'est ce principe que j'ai utilisé pour la collision entre mes neurotransmetteur et mes récépteurs), mais avec ma boucle while et la création de mes 4 objets, c'est devenu tout de suite beaucoup compliqué je trouvais

Je vous remercie énormement !!!
0
pas trouvé hélas. désolé pour l'aide incomplète.

J'ai fait ceci qui peut vous aider (le test de collision est bon pour une valeur X/abscisse comprise entre les paramètres ) mais comme c'est encore incomplet il faudra trouver l'astuce pour la bonne récursivité,
bonne chance:

<html>
<script>
let espaceTotal=100,/* pour simplifier l'exemple se fait sur une droite horizontale qui ne tient pas compte de la hauteur*/
 longueur=10,
 liste=[];
 
let aleatoire=function(max){
 return Math.floor(Math.random()*max);//---entier entre 0 et max-1 ici ce sera 0 et 99

}

//-- d'abord créer un premier élément dans la liste

liste.push( aleatoire(espaceTotal) ) ;

//-- toujours pour simplifier l'exemple je ne teste que l'écart horizontal
let generateur=function(nombre){
  for(let i=0;i<nombre;i++){//-- première boucle qui crée le nombre d'éléments désirés
    for(let j=0;j<liste.length;j++){//-- la boucle qui teste si un élément chevauche l'autre
      let aleaX=aleatoire(espaceTotal);
      let controle=true;
   
      if( aleaX > liste[j] && aleaX > liste[j]+longueur ){
  console.log('ok on peut rajouter ');
  controle==false;
      }
   if (controle!=false && aleaX< liste[j] && aleaX[j]+longueur <liste[j]){
     controle=false;
   }
   
   if(controle===false){
  liste.push(aleaX ) ;
   }else{
     
   }
    }
  }
}


generateur(12);
console.log('liste '+liste);
</script>
</html>
0
LeToulousain
31 mars 2020 à 16:53
Merci, j'ai tout de même reussi à mieux comprendre !
Bonne fin de journée !
0