def ConstructLines(self): for line in self.lines: line.Close() self.lines = [] usedRows = int(ceil(len(self.materialsData) / float(self.perRow))) pointsStart = self.GetLineStartingPoints() pConnect = self.GetLineConnectionPoint(pointsStart) y = self.top + self.materialsCont.top + self.materialsCont.height / 2 x = self.GetLineCirceOffset(y) width, height = self.parent.GetCurrentAbsoluteSize() self.pCircleIntersect = (width / 2 - x, pConnect[1]) pEnd = geo2.Vec2Subtract(self.pCircleIntersect, (1 * RADIUS_CONNECTOR_SMALL, 0)) if len(pointsStart) == 1: self.DrawLine((pointsStart[0], pEnd)) else: for point in pointsStart: if point[1] == pEnd[1]: self.DrawLine((point, geo2.Vec2Subtract(pConnect, (3, 0)))) else: self.DrawLine((point, (pConnect[0], point[1]), pConnect)) self.DrawLine((geo2.Vec2Add(pConnect, (3, 0)), pEnd)) if not self.connectorCircle: self.connectorCircle = MaterialGroupDashedCircle( parent=self.materialsCont, numSegments=len(self.materialsData), radius=RADIUS_CONNECTOR_SMALL, materialsByGroupID=((self.industryGroupID, self.materialsData), ), jobData=self.jobData) self.connectorCircle.left = pEnd[0] self.connectorCircle.top = pEnd[1] - RADIUS_CONNECTOR_SMALL self.UpdateState(animate=False)
def ApplyLineMargin(self, p1, p2, radius1, radius2): v = geo2.Vec2Subtract(p1, p2) vn = geo2.Vec2Normalize(v) l = geo2.Vec2Length(v) if not l: return (None, None) s = (radius1 + radius2) / l mp1 = geo2.Vec2Subtract(p1, geo2.Vec2Scale(vn, radius1)) mp2 = geo2.Vec2Add(p2, geo2.Vec2Scale(vn, radius2)) return (mp1, mp2)
def seg_intersect(line1, line2): a1, a2 = line1 b1, b2 = line2 da = geo2.Vec2Subtract(a2, a1) db = geo2.Vec2Subtract(b2, b1) dp = geo2.Vec2Subtract(a1, b1) dap = (-da[1], da[0]) denom = geo2.Vec2Dot(dap, db) if not denom: return False num = geo2.Vec2Dot(dap, dp) return geo2.Vec2Scale(geo2.Vec2Add(db, b1), num / denom)
def closest_point_on_seg(seg_a, seg_b, circ_pos): seg_v = geo2.Vec2Subtract(seg_b, seg_a) pt_v = geo2.Vec2Subtract(circ_pos, seg_a) if geo2.Vec2Length(seg_v) <= 0: raise ValueError, 'Invalid segment length' seg_v_unit = geo2.Vec2Normalize(seg_v) proj = geo2.Vec2Dot(seg_v_unit, pt_v) if proj <= 0: return seg_a if proj >= geo2.Vec2Length(seg_v): return seg_b proj_v = geo2.Vec2Scale(seg_v_unit, proj) closest = geo2.Vec2Add(proj_v, seg_a) return closest
def PlotLineTrace(self): self.Flush() if self.glowLine: self.glowLine.Flush() if self.lineType in (LINE_DASHED, LINE_DASHED_ACTIVE): self.PlotDashLine() elif self.lineType == LINE_SOLID: self.PlotSolidLine() else: return if self.lineType == LINE_DASHED_ACTIVE: vecDir = geo2.Vec2Subtract(self.toPosition, self.fromPosition) vecLength = geo2.Vec2Length(vecDir) vecDirNorm = geo2.Vec2Normalize(vecDir) r, g, b = self.GetRGB() GLOWCOLOR = (r, g, b, 1.0) GAPCOLOR = (r, g, b, 0.0) self.glowLine.AddPoint(self.fromPosition, GAPCOLOR) point = geo2.Vec2Add(self.fromPosition, geo2.Vec2Scale(vecDirNorm, vecLength * 0.5)) self.glowLine.AddPoint(point, GLOWCOLOR) self.glowLine.AddPoint(self.toPosition, GAPCOLOR) self.glowLine.textureWidth = vecLength uicore.animations.MorphScalar(self.glowLine, 'textureOffset', startVal=0.0, endVal=1.0, curveType=uiconst.ANIM_LINEAR, duration=2.0, loops=uiconst.ANIM_REPEAT)
def ScanForObjectLineOverlaps(hexMap, startPenalty=0, stopAtPenalty=None): penalty = startPenalty object_line_overlaps = [] objectIDs = sorted(hexMap.objectByID.keys()) for objectID in objectIDs: uiObject = hexMap.objectByID[objectID] objPos = (uiObject.left + hexMap.width / 2.0, uiObject.top + hexMap.height / 2.0) for connectionID, line in hexMap.connectionsByID.iteritems(): if objectID in connectionID: continue if not line.renderObject.vertices: continue p1x, p1y = line.renderObject.vertices[0].position p2x, p2y = line.renderObject.vertices[1].position pointOnLine = hexUtil.closest_point_on_seg((p1x, p1y), (p2x, p2y), objPos) dist_v = geo2.Vec2Subtract(pointOnLine, objPos) if geo2.Vec2Length(dist_v) < uiObject.hexSize: object_line_overlaps.append(uiObject) penalty += 100 if stopAtPenalty is not None and penalty >= stopAtPenalty: return (object_line_overlaps, penalty) return (object_line_overlaps, penalty)
def IsMouseHeadingTowards(self): owner = self.GetOwner() if owner.destroyed: return False mx, my = uicore.ScaleDpi(uicore.uilib.x), uicore.ScaleDpi( uicore.uilib.y) if len(self._mouseTrace) > SAMPLESIZE: self._mouseTrace.pop(0) self._mouseTrace.append((mx, my)) tl, tt, tw, th = (owner.displayX, owner.displayY, owner.displayWidth, owner.displayHeight) if tl <= mx <= tl + tw and tt <= my <= tt + th: return False oldX, oldY = self._mouseTrace[0] if (oldX, oldY) == (mx, my): return False mouseVector = geo2.Vec2Subtract((oldX, oldY), (mx, my)) dirX, dirY = geo2.Vec2Scale(mouseVector, 1000) hit = intersect((tl, tt), (tl + tw, tt + th), (mx, my), (mx - dirX, my - dirY)) if not hit: hit = intersect((tl + tw, tt), (tl, tt + th), (mx, my), (mx - dirX, my - dirY)) if hit: return True return False
def PlotDashLine(self): dashSize = 2.0 gapSize = 7.0 r, g, b = self.GetRGB() DASHCOLOR = (r, g, b, 1.0) GAPCOLOR = (r, g, b, 0.0) MARGIN = 16.0 * self.localScale vecDir = geo2.Vec2Subtract(self.toPosition, self.fromPosition) vecLength = geo2.Vec2Length(vecDir) vecDirNorm = geo2.Vec2Normalize(vecDir) p = MARGIN while p < vecLength - MARGIN: startPoint = geo2.Vec2Add(self.fromPosition, geo2.Vec2Scale(vecDirNorm, p - 0.5)) self.AddPoint(startPoint, GAPCOLOR) fromPoint = geo2.Vec2Add(self.fromPosition, geo2.Vec2Scale(vecDirNorm, p)) self.AddPoint(fromPoint, DASHCOLOR) p = min(vecLength - MARGIN, dashSize + p) toPoint = geo2.Vec2Add(self.fromPosition, geo2.Vec2Scale(vecDirNorm, p)) self.AddPoint(toPoint, DASHCOLOR) endPoint = geo2.Vec2Add(self.fromPosition, geo2.Vec2Scale(vecDirNorm, p + 0.5)) self.AddPoint(endPoint, GAPCOLOR) p += gapSize
def GetNewLineStartPos(self, node, childNode): pos = self._GetLinePosition(node) childPos = self._GetLinePosition(childNode) if node.nodeType == NODETYPE_GROUP: if childPos[1] == pos[1]: offset = node.GetGroupWidth() + 24 s = offset / geo2.Vec2Length(geo2.Vec2Subtract(childPos, pos)) pos = geo2.Vec2Lerp(pos, childPos, s) return (int(pos[0]), int(pos[1]))
def sphere_line_intersection(l1, l2, sp, r): x1, _, y1 = l1 x2, _, y2 = l2 x, _, y = sp A = x - x1 B = y - y1 C = x2 - x1 D = y2 - y1 dot = A * C + B * D len_sq = C * C + D * D param = dot / len_sq if param < 0: xx = x1 yy = y1 elif param > 1: xx = x2 yy = y2 else: xx = x1 + param * C yy = y1 + param * D diffVec = geo2.Vec2Subtract((x, y), (xx, yy)) return diffVec def square(f): return f * f p1 = p2 = None a = square(l2[0] - l1[0]) + square(l2[1] - l1[1]) + square(l2[2] - l1[2]) b = 2.0 * ((l2[0] - l1[0]) * (l1[0] - sp[0]) + (l2[1] - l1[1]) * (l1[1] - sp[1]) + (l2[2] - l1[2]) * (l1[2] - sp[2])) c = square(sp[0]) + square(sp[1]) + square(sp[2]) + square(l1[0]) + square( l1[1]) + square(l1[2]) - 2.0 * (sp[0] * l1[0] + sp[1] * l1[1] + sp[2] * l1[2]) - square(r) i = b * b - 4.0 * a * c from math import sqrt if i < 0.0: pass elif i == 0.0: p[0] = 1.0 mu = -b / (2.0 * a) p1 = (l1[0] + mu * (l2[0] - l1[0]), l1[1] + mu * (l2[1] - l1[1]), l1[2] + mu * (l2[2] - l1[2])) elif i > 0.0: mu = (-b + sqrt(i)) / (2.0 * a) p1 = (l1[0] + mu * (l2[0] - l1[0]), l1[1] + mu * (l2[1] - l1[1]), l1[2] + mu * (l2[2] - l1[2])) mu = (-b - sqrt(i)) / (2.0 * a) p2 = (l1[0] + mu * (l2[0] - l1[0]), l1[1] + mu * (l2[1] - l1[1]), l1[2] + mu * (l2[2] - l1[2])) return (p1, p2)
def __init__(self, parent, tileFrom, tileTo): self.tileFrom = tileFrom self.tileTo = tileTo self.parent = parent k = hackingUIConst.TILE_SIZE / 2.0 self.p0 = (self.tileFrom.left + k, self.tileFrom.top + k) self.p1 = (self.tileTo.left + k, self.tileTo.top + k) self.offset = geo2.Vec2Subtract(self.p1, self.p0) self.offset = geo2.Vec2Normalize(self.offset) self.center = geo2.Vec2Lerp(self.p0, self.p1, 0.5) self.lineType = self.GetLineType() self.line = uicls.VectorLine(parent=parent, align=uiconst.TOPLEFT) self.bleedSprite = None self.UpdateState()
def Update(self, *args): t = blue.os.GetSimTime() if t == self.lastUpdateTime: return if sm.GetService('michelle').GetBall(self.itemID) is None: self.Close() return self.UpdateBoxPosition() bracketPos = self.GetContainerPosition(self.bracket) boxPos = self.GetContainerPosition(self.floatingBox) lineTo = self.GetLineConnectionPointOnBox(bracketPos, self.floatingBox) cornerPos = geo2.Vec2Add(boxPos, lineTo) vec = geo2.Vec2Subtract(bracketPos, cornerPos) length = geo2.Vec2Length(vec) vec = geo2.Scale(vec, (length - uicore.ScaleDpi(ICON_SIZE / 2)) / length) self.line.translationTo = geo2.Vec2Add(vec, lineTo) self.line.translationFrom = lineTo
def GetVectorBetweenObjectsOnSameLevel(self, fromObjectID, toObjectID, parentObjectID, i=0): plotData = GetPlotDataForObject(parentObjectID, ignoreFixed=False) if fromObjectID in plotData: column1, row1 = plotData[fromObjectID] fromPos = hexUtil.hex_slot_center_position(column1, row1, self.isFlatTop, self.hexGridSize) elif self.parentMap and fromObjectID in self.parentMap.markersByID: fromPos = self.parentMap.markersByID[fromObjectID].unscaledPosition else: return if toObjectID in plotData: column2, row2 = plotData[toObjectID] toPos = hexUtil.hex_slot_center_position(column2, row2, self.isFlatTop, self.hexGridSize) elif self.parentMap and toObjectID in self.parentMap.markersByID: toPos = self.parentMap.markersByID[toObjectID].unscaledPosition else: return diffVec = geo2.Vec2Subtract(toPos, fromPos) diffVec = geo2.Vec2Scale(diffVec, 100000000000.0) cornerPoints = [] for i in xrange(6): if self.isFlatTop: outlineRad = self.width * 0.5 angle = 2.0 * math.pi / 6.0 * i else: outlineRad = self.height * 0.5 angle = 2.0 * math.pi / 6.0 * (i + 0.5) x_i = outlineRad * math.cos(angle) y_i = outlineRad * math.sin(angle) cornerPoints.append((x_i, y_i)) for i in xrange(6): p1 = cornerPoints[i] p2 = cornerPoints[i - 1] crossPoint = hexUtil.intersect_line_segments((p1, p2), ((0.0, 0.0), diffVec)) if crossPoint: return crossPoint
def RotateUpdateThread(self): try: while True: if self.rotateTarget is None: break distLeft = geo2.Vec2Length( geo2.Vec2Subtract(self.rotateTarget, self._rotateOffset)) if not distLeft: break moveProp = self._GetRotateSpeed() / blue.os.fps if math.fabs(distLeft) < self.kRotateStopDist: moveProp *= self.kRotateStopDist / math.fabs(distLeft) moveProp = min(moveProp, 1.0) self._rotateOffset = geo2.Lerp(self._rotateOffset, self.rotateTarget, moveProp) blue.synchro.Yield() finally: self.rotateUpdateThread = None
def UpdateState(self): tileFromData = self.tileFrom.tileData tileToData = self.tileTo.tileData if not tileFromData.IsFlippable() and not tileToData.IsFlippable(): colorFrom = colorTo = hackingUIConst.COLOR_BLOCKED elif hackingConst.TYPE_NONE in (tileFromData.type, tileToData.type): colorFrom = colorTo = hackingUIConst.COLOR_UNEXPLORED else: colorFrom = colorTo = hackingUIConst.COLOR_EXPLORED self.ShowBleed() widthFrom = widthTo = hackingUIConst.WIDTH_LINE if tileFromData.blocked or tileFromData.type == hackingConst.TYPE_DEFENSESOFTWARE: colorFrom = (0.0, 0.0, 0.0, 0.5) widthFrom = 5.0 if not (tileToData.blocked or tileToData.type == hackingConst.TYPE_DEFENSESOFTWARE): widthTo = 0.0 if tileToData.blocked or tileToData.type == hackingConst.TYPE_DEFENSESOFTWARE: colorFrom = (0.0, 0.0, 0.0, 0.5) widthTo = 5.0 if not (tileFromData.blocked or tileFromData.type == hackingConst.TYPE_DEFENSESOFTWARE): widthFrom = 0.0 uicore.animations.SpColorMorphTo(self.line, self.line.colorFrom, colorFrom, attrName='colorFrom') uicore.animations.SpColorMorphTo(self.line, self.line.colorTo, colorFrom, attrName='colorTo') uicore.animations.MorphScalar(self.line, 'widthFrom', self.line.widthFrom, widthFrom) uicore.animations.MorphScalar(self.line, 'widthTo', self.line.widthTo, widthTo) offset1 = self.GetLineOffsetAmount(self.tileFrom.tileData.type) p0 = geo2.Vec2Add(self.p0, geo2.Vec2Scale(self.offset, offset1)) self.line.translationFrom = p0 offset2 = self.GetLineOffsetAmount(self.tileTo.tileData.type) p1 = geo2.Vec2Subtract(self.p1, geo2.Vec2Scale(self.offset, offset2)) self.line.translationTo = p1
def PlotSolidLine(self): r, g, b = self.GetRGB() DASHCOLOR = (r, g, b, 1.0) GAPCOLOR = (r, g, b, 0.0) MARGIN = 16.0 * self.localScale vecDir = geo2.Vec2Subtract(self.toPosition, self.fromPosition) vecLength = geo2.Vec2Length(vecDir) vecDirNorm = geo2.Vec2Normalize(vecDir) startPoint = geo2.Vec2Add(self.fromPosition, geo2.Vec2Scale(vecDirNorm, MARGIN)) self.AddPoint(startPoint, GAPCOLOR) startPoint = geo2.Vec2Add(self.fromPosition, geo2.Vec2Scale(vecDirNorm, MARGIN + 8)) self.AddPoint(startPoint, DASHCOLOR) startPoint = geo2.Vec2Add( self.fromPosition, geo2.Vec2Scale(vecDirNorm, vecLength - MARGIN - 8)) self.AddPoint(startPoint, DASHCOLOR) startPoint = geo2.Vec2Add( self.fromPosition, geo2.Vec2Scale(vecDirNorm, vecLength - MARGIN)) self.AddPoint(startPoint, GAPCOLOR)
def _GetNodePosition(self, node): """ Returns node position scaled and offset so that the bottom-left most point is at (0, 0) """ vec = geo2.Vec2Subtract(node.GetPosition(), self._offset) return geo2.Vec2Scale(vec, TREE_SCALE)
def _GetNodePosition(self, node): vec = geo2.Vec2Subtract(node.GetPosition(), self._offset) return geo2.Vec2Scale(vec, TREE_SCALE)
def GetDimensions(self): p0, p1 = self.GetBoundingBox() return geo2.Vec2Subtract(p1, p0)
boxPoint = (x, yMin) elif case == CASE3: boxPoint = (xMax, yMin) elif case == CASE4: boxPoint = (xMin, y) elif case == CASE5: boxPoint = (xMax, y) elif case == CASE6: boxPoint = (xMin, yMax) elif case == CASE7: boxPoint = (x, yMax) elif case == CASE8: boxPoint = (xMax, yMax) elif case == CASE9: return 0.0 return geo2.Vec2Length(geo2.Vec2Subtract(point, boxPoint)) def GetLineConnectionPointOnBox(self, point, box): case = self.ClassifyPointNearBox(point, box) xMax, yMax = uicore.ScaleDpi(box.width) * 0.5, uicore.ScaleDpi(box.height) * 0.5 xMin, yMin = -xMax, -yMax if case == CASE1: boxPoint = (xMin, yMin) elif case == CASE2: boxPoint = (0, yMin) elif case == CASE3: boxPoint = (xMax, yMin) elif case == CASE4: boxPoint = (xMin, 0) elif case == CASE5: boxPoint = (xMax, 0)
def segment_circle(seg_a, seg_b, circ_pos, circ_rad=1): closest = closest_point_on_seg(seg_a, seg_b, circ_pos) dist_v = geo2.Vec2Subtract(circ_pos, closest) return dist_v