def reflect(self): a = self._points[0] - self._position b = self._points[2] - self._position c = (a - b).normalized() a = self._points[1] - self._position b = self._points[3] - self._position a = 2 * QVector2D.dotProduct(a, c) * c - a b = 2 * QVector2D.dotProduct(b, c) * c - b self._points[1] = a + self._position self._points[3] = b + self._position
def isBetween(self, p1, p2, max_offset, offsetBeyondEnds=False): if offsetBeyondEnds and any( self.distanceTo(p) <= max_offset for p in (p1, p2)): return True q = self.toQPointF() q1 = p1.toQPointF() q2 = p2.toQPointF() vp1p2 = QVector2D(q2 - q1) return QVector2D.dotProduct(vp1p2, QVector2D(q - q1)) >= 0 \ and QVector2D.dotProduct(vp1p2, QVector2D(q - q2)) <= 0 \ and QVector2D(q).distanceToLine(QVector2D(q1), vp1p2.normalized()) <= max_offset
def orthProj(self, p1, p2): q1 = p1.toQPointF() q2 = p2.toQPointF() vdir = QVector2D(q2 - q1).normalized() vq1q = QVector2D(self.toQPointF() - q1) vq1h = QVector2D.dotProduct(vq1q, vdir) * vdir return RadarCoords.fromQPointF(q1 + QPointF(vq1h))
def rotate(self, direction): theta = -2.0 / 360.0 points = [] a = QVector2D(math.cos(theta), -math.sin(theta)) b = QVector2D(math.sin(theta), math.cos(theta)) c = QVector2D(math.cos(-theta), -math.sin(-theta)) d = QVector2D(math.sin(-theta), math.cos(-theta)) if direction: for i in self._points: x = QVector2D.dotProduct(i - self._position, a) y = QVector2D.dotProduct(i - self._position, b) points.append(QVector2D(x, y) + self._position) self._points = points else: for i in self._points: x = QVector2D.dotProduct(i - self._position, c) y = QVector2D.dotProduct(i - self._position, d) points.append(QVector2D(x, y) + self._position) self._points = points
def mouseMoveEvent(self, event): if self.__dragActive: mousePos = self.view.mapToScene(self.view.mapFromGlobal(QCursor.pos())) vec1 = QVector2D(mousePos) vec1.normalize() trans = QTransform() trans.rotate(self.rotation()) vec2 = QVector2D(self.p2 * trans) vec2.normalize() angle = math.acos(max(-1, min(1, QVector2D.dotProduct(vec1, vec2)))) * 180 / math.pi # clockwise rotation if vec1.y() * vec2.x() < vec1.x() * vec2.y(): angle *= -1 angle = (self.rotation() + angle) % 360 self.setRotation(angle)
def mouseMoveEvent(self, event): if self.__dragActive: mousePos = self.view.mapToScene(self.view.mapFromGlobal(QCursor.pos())) vec1 = QVector2D(mousePos) vec1.normalize() trans = QTransform() trans.rotate(self.rotation()) vec2 = QVector2D(self.p2 * trans) vec2.normalize() angle = math.acos(max(-1, min(1, QVector2D.dotProduct(vec1, vec2)))) * 180 / math.pi # clockwise rotation if vec1.y() * vec2.x() < vec1.x() * vec2.y(): angle *= -1 angle = (self.rotation() + angle) % 360 self.setRotation(angle)
def intersectsCircle(self, position, rect, size): size_sqr = size**2 scene_translation = self.startSocket().sceneTransform() connection_rect = scene_translation.mapRect(self._rect) # Line circle intersection test http://i.stack.imgur.com/P556i.png if connection_rect.contains(rect) or ( connection_rect.width() <= size or connection_rect.height() <= size): connection_path = scene_translation.map(self._path) simplified_path = connection_path.simplified() element_count = simplified_path.elementCount() - 1 # In case path is linear if element_count == -1: simplified_path = connection_path element_count = simplified_path.elementCount() previous_point = None for i in range(element_count): element = simplified_path.elementAt(i) point = QPointF(element.x, element.y) previous_point, _previous_point = point, previous_point if _previous_point is None: continue to_position = QVector2D(position - _previous_point) to_end = QVector2D(point - _previous_point) to_end_length = to_end.length() if not to_end_length: continue projection = QVector2D.dotProduct(to_position, to_end) / to_end_length # Projected point lies within this segment if 0 <= projection <= to_end_length: dist_path_sqr = to_position.lengthSquared() - projection**2 if dist_path_sqr < size_sqr: return self
def chooseMove(self, init_position, sectors, borders=None): smax, lrange, hrange = self.findTarget(sectors) best_path = None #print ("target", target) #print (angle) steps = 5 # FIXME se il fantino e` preciso fare uno scan ulteriore # intorno a +- 2.5 gradi dal best (da valutare con semaring dovuto al cavallo) for anAngle in range(lrange, hrange, steps): collisions = 0 origin = QVector2D(self.pos.x(), self.pos.y()) min_dist = origin.distanceToPoint(self.target) current_best = [min_dist, 0, origin, anAngle] #print("Angolo", anAngle, origin) path = QPainterPath() path.addEllipse(origin.toPoint(), 20, 20) dv = QVector2D(math.cos(math.radians(anAngle)), math.sin(math.radians(anAngle))) #print ("dV", dv) #print ("orig", origin) # for it in self.scene().items(): # if it.type() == QGraphicsItem.UserType + 2: # if it == self: # continue # print (it.boundingRect()) # pen = QPen(Qt.red, 5, Qt.SolidLine) # self.scene().addPath(it.shape(), pen) # if path.intersects(it.shape()): # print("COLLISION ", it.id) # return iterS = 0 while iterS <= int(smax): #for i in range(int(smax)): origin += dv #print ("origin", iterS, origin) path.moveTo(origin.toPoint()) for it in self.scene().items(): if it.type() == QGraphicsItem.UserType + 2: if it == self: continue if path.intersects(it.mapToScene(it.shape())): collisions += 1 #print ("COLLISION ", it.id) r = QVector2D(it.pos.x() - origin.x(), it.pos.y() - origin.y()).normalized() cos_theta = QVector2D.dotProduct(dv, r) dv_mod_squared = (smax - iterS) * 2 * self.FRICTION * cos_theta * cos_theta #print ("before ", iterS, dv_mod_squared) #print (cos_theta, r) dv_coll = cos_theta * r dv -= dv_coll origin += dv iterS += 0.5 * dv_mod_squared / self.FRICTION #print ( "after ", iterS, smax) #print ("new dv ", dv) break # FIXME loop solo sui bordi associati al settore for ib, b in enumerate(borders): #FIXME riduci velocita in caso di urto #print ("border ", ib) if path.intersects(b.boundingRect()): #print ("Collision ", ib) new_angle = collisionAngle2(b.line, QLineF((origin+22*dv).toPointF(), origin.toPointF())) #print ("NEW ANGLE ", new_angle) dv = QVector2D(math.cos(new_angle), math.sin(new_angle)) #cos_theta = abs(math.cos(math.radians(angle))) #print("angle after: ", angle, cos_theta) # simulare perdita di energia nel rimbalzo #print ("intersect with:", ib, path.currentPosition()) #cos_theta = QVector2D.dotProduct(b.direction, dv) #print ("angle after: ", math.degrees(math.acos(cos_theta))) #dv -= 2 * dv * cos_theta #dv = dv.normalized() #print ("dv ", dv) origin += dv break #print (collisions) tmp_dist = origin.distanceToPoint(self.target) #+ collisions * 200 #print (tmp_dist) if tmp_dist < min_dist: min_dist = tmp_dist current_best = [min_dist, iterS, origin, anAngle] #print (current_best) iterS += 1 #current_best[0] += 0.5*origin.distanceToPoint(sectors[self.currentSector+1].guide) sect = -1 for iSector, s in enumerate(sectors): if s.isIn(origin.toPointF()): sect = iSector break me = [sect, origin.distanceToPoint(sectors[sect+1].guide)] overtakes = 0 for it in self.scene().items(): if it == self: continue if it.type() == QGraphicsItem.UserType + 2: sect = -1 for iSector, s in enumerate(sectors): if s.isIn(origin.toPointF()): sect = iSector break if sect < me[0]: overtakes += 1 elif sect == me[0]: dist = it.pos.distanceToPoint(sectors[sect+1].guide) if dist > me[1]: overtakes += 1 # FIXME modulare questo numero in base alla posizione # se e` dietro se ne frega delle collisioni delta = - collisions * 100 print (delta) if (10 - overtakes) < init_position: delta += (init_position - 10 + overtakes) * 20 print (delta) current_best[0] -= delta print ("{}".format(self.id), current_best, self.target, origin) if best_path is None: best_path = current_best else: if current_best[0] < best_path[0]: best_path = current_best elif abs(current_best[0] - best_path[0])/current_best[0] < 0.05: if current_best[1] < best_path[1]: best_path = current_best # salva il percorso con minore distanza dalla guida (poi aggiungere la distanza anche dal prossimo punto) # minore spazio percorso #self.scene().addLine(QLineF(self.pos.x(), origin.x(), self.pos.y(), origin.y())) #speed = 40 #direction = -85 print ("BEST ", best_path) speed = math.sqrt(2*best_path[1]*self.FRICTION) #print (speed) #self.min_dist = best_path[0] # FIXME errore casuale gaussiano in base alla precisione # del cavallo self.initKinematics(best_path[3], speed)
def move(self, sectors): #print ("{} {}".format(self.id, (self.v.length()))) if self.v.length() < 3.5: self.v = QVector2D() #self.scene().move_ended.emit() return #print ("{} non si muove".format(self.id)) #return #else: # print ("{} v: {}".format(self.id, self.v.length())) #smax = self.v.length() * self.dt #orig_pos = self.pos steps = 1 self.setRotation(math.degrees(math.atan2(self.v.y(), self.v.x()))) for _ in range(steps): ds = self.v * self.dt / steps newpos = self.pos + ds items = self.scene().collidingItems(self) #print ("COLLISIONI ", len(items), newpos) if len(items) != 0: for it in items: if it.type() == QGraphicsItem.UserType + 1: tmp = (self.pos + 22*self.v.normalized()) test = QLineF(tmp.x(), tmp.y(), self.pos.x(), self.pos.y()) #print ("test", test) new_angle = collisionAngle2(it.line, test) #cos_theta = abs(math.cos(math.radians(angle))) #self.v -= 2 * self.v * cos_theta self.v = self.v.length() * QVector2D(math.cos(new_angle), math.sin(new_angle)) ds = self.v * self.dt / steps newpos = self.pos + ds break elif it.type() == QGraphicsItem.UserType + 2: #print ("COLLISION ", it.id) r = QVector2D(it.pos.x() - self.pos.x(), it.pos.y() - self.pos.y()).normalized() cos_theta = QVector2D.dotProduct(self.v.normalized(), r) #print (cos_theta, r, self.v) if cos_theta > 0: #self.setRotation(math.degrees(new_angle)) delta_v = self.v.length() * cos_theta * r self.v -= delta_v it.v += delta_v newpos = it.pos + it.v * self.dt/steps it.setPos(newpos.toPointF()) ds = self.v * self.dt / steps newpos = self.pos + ds #print ("POST BREAK") self.currentFrame -= int(ds.length()) if self.currentFrame < 0: self.currentFrame = 99 #self.currentFrame % 100 self.update(0, 0, self.RADIUS, self.RADIUS) self.pos = newpos #print (newpos) self.setPos(self.pos.toPoint()) #self.mapToParent(0, -(3 + math.sin(self.speed) * 3))) #print ("deltaV ", self.dt * self.FRICTION / steps) self.v -= self.v.normalized() * self.dt * self.FRICTION / steps if self.v.length() < 3.5: self.v = QVector2D() self.scene().move_ended.emit() if sectors[self.currentSector + 1].isIn(self.pos.toPointF()): self.currentSector += 1 self.target = sectors[self.currentSector].guide print ("TARGET SET ", self.target) if sectors[self.currentSector].isFinish: self.scene().race_ended.emit(self.id)