objets/CPolygone.js

/*
 * MathGraph32 Javascript : Software for animating online dynamic mathematics figures
 * https://www.mathgraph32.org/
 * @Author Yves Biton (yves.biton@sesamath.net)
 * @License: GNU AGPLv3 https://www.gnu.org/licenses/agpl-3.0.html
 */
import NatObj from '../types/NatObj'
import Vect from '../types/Vect'
import { cens, round3dg, zero13 } from '../kernel/kernel'
import CLignePolygonaleAncetre from './CLignePolygonaleAncetre'
import { appartientSegment, coefficientsPointInterieur, coefficientsPointSurSegment, estInterieurATriangle } from 'src/kernel/kernelVect'

export default CPolygone

/**
 * Classe polygone
 * @constructor
 * @param {CListeObjets} listeProprietaire  La liste propriétaire.
 * @param {CImplementationProto} impProto  null ou la construction propriétaire.
 * @param {boolean} estElementFinal  true si élément final de construction.
 * @param {Color} couleur  La couleur.
 * @param {boolean} masque  true si l'objet est masqué.
 * @param {StyleTrait} style  Le style du tracé.
 * @param {CNoeudPointeurSurPoint} colPoints  Tableau de CNoeudPointeurSurPoint qui donne les sommets.
 * @returns {CPolygone}
 */
function CPolygone (listeProprietaire, impProto, estElementFinal, couleur, masque, style, colPoints) {
  if (arguments.length === 1) CLignePolygonaleAncetre.call(this, listeProprietaire)
  else CLignePolygonaleAncetre.call(this, listeProprietaire, impProto, estElementFinal, couleur, masque, style, colPoints)
}
CPolygone.prototype = new CLignePolygonaleAncetre()
CPolygone.prototype.constructor = CPolygone
CPolygone.prototype.superClass = 'CLignePolygonaleAncetre'
CPolygone.prototype.className = 'CPolygone'

CPolygone.prototype.getClone = function (listeSource, listeCible) {
  const colClone = new Array(this.nombrePoints)
  for (let i = 0; i < this.nombrePoints; i++) {
    const noeud = this.colPoints[i]
    colClone[i] = noeud.getClone(listeSource, listeCible)
  }
  const ind1 = listeSource.indexOf(this.impProto)
  return new CPolygone(listeCible, listeCible.get(ind1, 'CImplementationProto'),
    this.estElementFinal, this.couleur, this.masque, this.style.getClone(), colClone)
}
CPolygone.prototype.createg = function () {
  let style = ''
  const stroke = this.style.stroke
  if (stroke.length !== 0) style += 'stroke-dasharray:' + stroke + ';'
  const strokewidth = this.style.strokeWidth
  style += 'stroke-width:' + strokewidth + ';'
  // style += "stroke:"+this.couleur.rgb()+";"; Modifié version 4.9.9.4
  // style += 'stroke:' + this.color + ';' // Modifié version 6.9.1
  style += 'stroke:' + this.color + ';opacity:' + this.couleur.opacity + ';'
  style += 'fill:none'
  return cens('polygon', {
    points: this.getPoints(),
    style,
    // Ligne suivante modifiée version 6.5.2
    // 'pointer-events': 'none'
    'pointer-events': this.pointerevents
  })
}
CPolygone.prototype.getPoints = function () {
  let points = ''
  // Pour un polygone, le dernier point est le même que le premier mais pas pour svg
  for (let i = 0; i < this.nombrePoints - 1; i++) {
    points += round3dg(this.absPoints[i]) + ',' + round3dg(this.ordPoints[i]) + ' '
  }
  return points
}
// Version JavaScript : trace est spécifique pour CPolygone et CLigneBrisee
CPolygone.prototype.trace = function (svg) {
  const g = this.createg()
  g.setAttribute('id', this.id)
  svg.appendChild(g)
  this.g = g
}
CPolygone.prototype.update = function () {
  const g = this.g
  g.setAttribute('points', this.getPoints())
}
CPolygone.prototype.confonduAvec = function (p) {
  let ptp1, ptp2, i, j, resultat

  if (p.className === this.className) {
    let nombrePoints = this.nombrePoints
    if (nombrePoints !== p.nombrePoints) return false
    // On regarde si un polynôme a déjà été créé avec les mêmes sommets
    // dans le  même ordre. On ne regarde pas le dernier sommet qui
    // est le même que le premier}
    nombrePoints--
    j = 0
    do {
      ptp1 = this.colPoints[0].pointeurSurPoint
      ptp2 = p.colPoints[j % nombrePoints].pointeurSurPoint
      resultat = (ptp1 === ptp2)
      i = 1
      while (resultat && (i <= nombrePoints - 1)) {
        ptp1 = this.colPoints[i].pointeurSurPoint
        ptp2 = p.colPoints[(i + j) % nombrePoints].pointeurSurPoint
        resultat = resultat && (ptp1 === ptp2)
        i++
      }
      j++
    }
    while ((j !== nombrePoints) && !resultat)

    if (resultat) return true
    // On regarde en tournant dans l'autre sens
    j = 0
    do {
      ptp1 = this.colPoints[nombrePoints - 1].pointeurSurPoint
      ptp2 = p.colPoints[j % nombrePoints].pointeurSurPoint
      resultat = (ptp1 === ptp2)
      i = 1
      while (resultat && (i <= nombrePoints - 1)) {
        ptp1 = this.colPoints[nombrePoints - 1 - i].pointeurSurPoint
        ptp2 = p.colPoints[(i + j) % nombrePoints].pointeurSurPoint
        resultat = resultat && (ptp1 === ptp2)
        i++
      }
      j++
    }
    while ((j !== nombrePoints) && !resultat)
    return resultat
  } else return false
}

CPolygone.prototype.abscisseMinimale = function () {
  return 0
}
CPolygone.prototype.abscisseMaximale = function () {
  return 1 - 1e-12
}
CPolygone.prototype.getNature = function () {
  return NatObj.NPolygone
}
CPolygone.prototype.lieALigneFermee = function () {
  return true
}
/**
 * Fonction renvoyant true si le point de coordonnées (x; y) est intérieur au polygône
 * c'est à dire s'il est sur un des côtés ou si la somme des mesures principales d'angle orienté
 * est un multiple impair de 2*pi.
 */
CPolygone.prototype.pointInterieur = function (x, y) {
  let sommeang = 0
  const taille = this.colPoints.length
  for (let i = 0; i < taille - 1; i++) {
    const noeud1 = this.colPoints[i]
    const x1 = noeud1.pointeurSurPoint.x
    const y1 = noeud1.pointeurSurPoint.y
    const noeud2 = this.colPoints[i + 1]
    const x2 = noeud2.pointeurSurPoint.x
    const y2 = noeud2.pointeurSurPoint.y
    if (appartientSegment(x, y, x1, y1, x2, y2)) return true
    const u = new Vect(x, y, x1, y1)
    const v = new Vect(x, y, x2, y2)
    sommeang += u.mesureAngleVecteurs(v)
  }
  // Modifié version 7.3 pour optimisation
  // const q = Math.floor(sommeang / (2 * Math.PI) + 0.5)
  const q = Math.round(sommeang / (2 * Math.PI))
  // Modifié version 4.8
  // return q != 2*Math.floor(q/2);
  return !zero13(q - 2 * Math.floor(q / 2))
}
CPolygone.prototype.determinePositionInterieure = function (x, y, indicePremierSommet, estSurCote, alpha, beta, gamma) {
  let i, nd1, nd2, nd3, nd4
  const nbSommets = this.nombrePoints - 1
  for (i = 0; i < nbSommets; i++) {
    nd1 = this.colPoints[i]
    const b = nd1.pointeurSurPoint
    nd2 = this.colPoints[i + 1]
    const c = nd2.pointeurSurPoint
    if (appartientSegment(x, y, b.x, b.y, c.x, c.y)) {
      indicePremierSommet.setValue(i)
      coefficientsPointSurSegment(x, y, b.x, b.y, c.x, c.y, alpha, beta)
      estSurCote.setValue(true)
      return true
    }
  }
  const nda = this.colPoints[0]
  const a = nda.pointeurSurPoint
  for (i = 1; i < nbSommets - 1; i++) {
    nd3 = this.colPoints[i]
    const d = nd3.pointeurSurPoint
    nd4 = this.colPoints[i + 1]
    const e = nd4.pointeurSurPoint
    if (estInterieurATriangle(x, y, a.x, a.y, d.x, d.y, e.x, e.y)) {
      indicePremierSommet.setValue(i)
      // En appelant I le point d'intersection on calcule les coordonnées barycentriques du point
      // de coordonnées (x; y) par rapport au triangle ICD
      coefficientsPointInterieur(x, y, a.x, a.y, d.x, d.y, e.x, e.y, alpha, beta, gamma)
      estSurCote.setValue(false)
      return true
    }
  }
  return false
}
CPolygone.prototype.chaineDesignation = function () {
  return 'desPolygone'
}