def step(self, x, y, direction, brightness): """ step is called many times while iterating over the loaded bitmap in each step we calculate a squiggle based on position x,y with given brightness in the bitmap. direction is a direction vector indicating what direction we are moving in. calculate a new squiggle in the circle generation process :param x: x pos in bitmap that calculation should be based on :param y: y pos in bitmap that calculation should be based on :param direction: in what direction are we moving? :param brightness: gray value in the bitmap at x,y :return: potentially modified step size """ stepSize = Mapping.linexp(brightness, 0, 255, self.minStepSize, self.maxStepSize) stepSize = Mapping.linlin(stepSize, 1, 10, 1, 10 / self.detail) self.previous_stepsize = stepSize amplitudeSize = Mapping.linlin(brightness, 0, 255, self.strength, 0) if self.prevPos is None: self.path = QPainterPath() self.path.moveTo(x, y) self.prevPos = np.array([[ x, ], [ y, ]]) else: newPos = np.array([[ x, ], [ y, ]]) dirx = direction[0][0] diry = direction[1][0] ortho_dir = np.array([[-diry], [dirx] ]) * self.disturbance_direction disturbance = ortho_dir * amplitudeSize disturbedPos = (self.prevPos + newPos) / 2 + disturbance if not self.clipToBitmap or (self.clipToBitmap and not Circle( x, y, amplitudeSize).edges(self.width, self.height)): self.path.quadTo(disturbedPos[0][0], disturbedPos[1][0], newPos[0][0], newPos[1][0]) else: self.path.moveTo(newPos[0][0], newPos[1][0]) self.prevPos = newPos self.disturbance_direction = -self.disturbance_direction return max(int(stepSize), 1)
def step(self, x, y, direction, brightness): """ step is called many times while iterating over the loaded bitmap in each step we calculate a circle based on position x,y with given brightness in the bitmap. direction is a direction vector indicating what direction we are moving in. calculate a new circle in the circle generation process :param x: x pos in bitmap that calculation should be based on :param y: y pos in bitmap that calculation should be based on :param direction: in what direction are we moving? :param brightness: gray value in the bitmap at x,y :return: potentially modified step size """ r = Mapping.linexp(brightness, self.minBrightness, self.maxBrightness, self.maxRadius, self.minRadius) if not r: r = self.minRadius stepsize = int( Mapping.linlin(brightness, self.minBrightness, self.maxBrightness, self.minStepSize, self.maxStepSize)) if not self.clipToBitmap or (self.clipToBitmap and not Circle( x, y, r).edges(self.width, self.height)): item = QGraphicsEllipseItem(x - r, y - r, r * 2, r * 2) pen = QPen() pen.setWidth(self.strokeWidth) item.setPen(pen) self.group.addToGroup(item) return max(int(stepsize), 1)
def skip(self, x, y, direction, brightness): """ similar to step, but explicitly asking to skip generation of a circle (e.g. because brightness constraints are not met) this allows the method to update its internal state to keep track of what is happening :param x: x pos in bitmap that the calculation should be based on :param y: x pos in bitmap that the calculation should be based on :param direction: direction we were moving in :param brightness: gray value of x,y in bitmap :return: potentially modified step size """ stepsize = int( Mapping.linlin(brightness, self.minBrightness, self.maxBrightness, self.minStepSize, self.maxStepSize)) return max(int(stepsize), 1)
def makeSquiggles(self, image): """ actual calculations :param image: bitmap to squigglify :return: """ noOfLines = self.parent.noOfLines.value() height = image.height() width = image.width() amplitude = self.parent.strength.value() strokeWidth = self.parent.lineWidth.value() detail = self.parent.detail.value() invertColors = self.parent.invertColors.checkState() == Qt.Checked verticalSquiggles = self.parent.verticalSquiggles.checkState( ) == Qt.Checked maxBrightness = self.parent.maxBrightness.value() minBrightness = self.parent.minBrightness.value() self.removeOldGraphicsItems() group = QGraphicsItemGroup() finalRow = False minStepSize = self.parent.minStepSize.value() maxStepSize = self.parent.maxStepSize.value() # TODO: too much code duplication! path = QPainterPath() if not verticalSquiggles: scaledystep = max(1, height / noOfLines) for y in frange(0, height, scaledystep): if fabs(y - height) < 1e-3 or y >= height: finalRow = True x = 0 disturbance_direction = -1 prevX = 0 prevY = y while x < width: disturbance_direction = -disturbance_direction grayvalue = qGray(image.pixel(x, y)) if invertColors: grayvalue = 255 - grayvalue stepSize = Mapping.linexp(grayvalue, 0, 255, minStepSize, maxStepSize) stepSize = Mapping.linlin(stepSize, 1, 10, 1, 10 / detail) amplitudeSize = Mapping.linlin(grayvalue, 0, 255, amplitude, 0) if x == 0: path = QPainterPath() path.moveTo(x, y) x = prevX + stepSize newY = prevY + amplitudeSize * disturbance_direction if minBrightness <= grayvalue <= maxBrightness: path.quadTo((prevX + x) / 2, newY, x, prevY) else: path.moveTo(x, prevY) if x >= width: item = QGraphicsPathItem(path) pen = QPen() pen.setWidth(strokeWidth) item.setPen(pen) group.addToGroup(item) prevX = x prevY = y if finalRow: break else: scaledxstep = max(1, width / noOfLines) for x in frange(0, width, scaledxstep): if fabs(x - width) < 1e-3 or x >= width: finalRow = True y = 0 disturbance_direction = -1 prevX = x prevY = 0 while y < height: disturbance_direction = -disturbance_direction grayvalue = qGray(image.pixel(x, y)) if invertColors: grayvalue = 255 - grayvalue stepSize = Mapping.linexp(grayvalue, 0, 255, minStepSize, maxStepSize) stepSize = Mapping.linlin(stepSize, 1, 10, 1, 10 / detail) amplitudeSize = Mapping.linlin(grayvalue, 0, 255, amplitude, 0) if y == 0: path = QPainterPath() path.moveTo(x, y) y = prevY + stepSize newX = prevX + amplitudeSize * disturbance_direction if minBrightness <= grayvalue <= maxBrightness: path.quadTo(newX, (prevY + y) / 2, prevX, y) else: path.moveTo(x, prevY) if y >= height: item = QGraphicsPathItem(path) pen = QPen() pen.setWidth(strokeWidth) item.setPen(pen) group.addToGroup(item) prevX = x prevY = y if finalRow: break self.addNewGraphicsItems(group)