I was wondering if anybody might be able to shed some light on this problem, I'm quite new to scala and generally non R programming, so i'm still learning some of the ropes so to speak.
What i'm trying to do is plot a 2D array, so a grid of squares on a gray scale with a darker colour representing a higher value. I have a csv file of x and y locations on the grid and a third value z which will be represented by the colour.
I've written two pieces of code which do what I want, one extracts data from a csv file, the other plots the type of data that is extracted. The problem I have is getting them to work together.
So piece of code 1 extracts data which is as follows:
x, y, z
50, 16, 52
21, 25, 29
13, 12, 445
etc...
code:
import scala.io.Source
import java.io._
///////extract the data
object DataExtractor extends App {
def using[T <: Closeable, R](resource: T)(block: T => R): R = {
try { block(resource) }
finally { resource.close() }
}
for (line <- io.Source.fromFile("C://~//TestData.csv").getLines.drop(1)) {
val array = line.split(",")
try {
val xloc = array(0)
val yloc = array(1)
val intense = array (2)
}catch { case ex: Exception => }
}
}
This gives me a value from each line of the csv the x axis location (xloc), y axis (yloc) and what will be the intensity value (intense) in order to plot how darkly shaded the grid square is.
The second piece of code plots a 2D array using "processing"
/////////plotting data
import processing.core._
class FT extends processing.core.PApplet {
val xloc = 9 //define locations
val yloc = 1
val intense = 4 //define intensity of colour
var grid: Array[Array[Cell]] = _
var cols: Int = 100 // grid size
var rows: Int = 100
override def setup() {
size(200, 200) //window size
grid = Array.ofDim[Cell](cols, rows)
for (i <- 0 until cols; j <- 0 until rows) {
grid(i)(j) = new Cell(i * 10, j * 10, 10, 10, i + j) //cell size
}
}
override def draw() {
background(0)
for (i <- 0 until cols; j <- 0 until rows) {
grid(i)(j).display()
grid(i)(j).height()
grid(i)(j).xl()
grid(i)(j).yl()
}
}
class Cell(var x: Float,
var y: Float,
var w: Float,
var h: Float,
var strength: Float) {
def display() {
stroke(255)
fill(strength)
rect(x, y, w, h)
}
def height() {
strength = intense
}
def xl() {
x = xloc
}
def yl() {
y = yloc
}
}
}
As you can see, in my second piece of code i've given xloc, yloc and intense arbitrary values. What i'm trying to do is to loop through a csv file and for each line plug in the data to the plotting code so the final result is a grid with differing colour intensities based on the x, y and z values in the csv file.
Any help will be much appreciated as i'm still trying to figure out how one links chunks of code together in scala.
Edit:
So what i've tried is to integrate the two pieces of code, however I'm running into a new problem which is that scala will not initialize a local varaible within a method (var grid). But by moving grid outside of the loop it can no longer access the Cell class...any pointers or ideas would be much appreciated
import processing.core._
import scala.io.Source
import java.io._
class FT extends processing.core.PApplet {
for (line <- io.Source.fromFile("C:~TestData.csv").getLines.drop(1)) {
try {
val array = line.split(",")
var xloct = array(0)
var yloct = array(1)
var intenset = array (2)
val xloc = xloct.toFloat
val yloc = yloct.toFloat
val intense = intenset.toFloat
var grid: Array[Array[Cell]] =_ // error "local variables must be initialized"
var cols: Int = 100 // grid size
var rows: Int = 100
def setup() {
size(200, 200) //window size
grid = Array.ofDim[Cell](cols, rows)
for (i <- 0 until cols; j <- 0 until rows) {
grid(i)(j) = new Cell(i * 10, j * 10, 10, 10, i + j) //cell size
}
}
def draw() {
background(0)
for (i <- 0 until cols; j <- 0 until rows) {
grid(i)(j).display()
grid(i)(j).height()
grid(i)(j).xl()
grid(i)(j).yl()
}
}
class Cell(var x: Float,
var y: Float,
var w: Float,
var h: Float,
var strength: Float) {
def display() {
stroke(255)
fill(strength)
rect(x, y, w, h)
}
def height() {
strength = intense
}
def xl() {
x = xloc
}
def yl() {
y = yloc
}
}
} catch { case ex: Exception => }
}
}
Related
I am trying to simply show a video removing part of its background which is meant to be transparent. I've tried several approaches courtesy of Stack Overflow, and so far they are all sub-par. The one that came closest to the results I'm seeking is the one in this link: ARKit / SpriteKit - set pixelBufferAttributes to SKVideoNode or make transparent pixels in video (chroma-key effect) another way
However, as sensible as the approach is, and as much as it seems to be working for the person who asked the question, in my case it only turns the whole video white.
My strategy is to show the video and add the effect as follows:
func setVideoNode(named name: String, in node: SCNNode, with imageReference: ARReferenceImage?, size: CGSize = CGSize(width: 500, height: 320), extension ext: String = "mp4") {
let nodeWidth = imageReference!.physicalSize.width
let nodeHeigth = imageReference!.physicalSize.height
guard let videoUrl = Bundle.main.url(forResource: name, withExtension: ext) else {
print("Guard Fail")
return
}
self.currentPlayer = AVPlayer(url: videoUrl)
let videoNode = SKVideoNode(avPlayer: self.currentPlayer)
videoNode.size = size
videoNode.name = name
videoNode.yScale = -1.0
videoNode.play()
let effectNode = SKEffectNode()
effectNode.addChild(videoNode)
effectNode.filter = colorCubeFilterForChromaKey(hueAngle: 0)
let planeGeometry = SCNPlane(width: nodeWidth, height: nodeHeigth)
planeGeometry.firstMaterial?.diffuse.contents = effectNode
planeGeometry.firstMaterial?.isDoubleSided = true
let planeNode = SCNNode()
planeNode.geometry = planeGeometry
planeNode.position = SCNVector3(planeNode.position.x + 1, 0.5, 0)
planeNode.eulerAngles.x = -.pi / 2
node.addChildNode(planeNode)
self.currentPlayer.play()
}
func RGBtoHSV(r : Float, g : Float, b : Float) -> (h : Float, s : Float, v : Float) {
var h : CGFloat = 0
var s : CGFloat = 0
var v : CGFloat = 0
let col = UIColor(red: CGFloat(r), green: CGFloat(g), blue: CGFloat(b), alpha: 1.0)
col.getHue(&h, saturation: &s, brightness: &v, alpha: nil)
return (Float(h), Float(s), Float(v))
}
func colorCubeFilterForChromaKey(hueAngle: Float) -> CIFilter {
let hueRange: Float = 20 // degrees size pie shape that we want to replace
let minHueAngle: Float = (hueAngle - hueRange/2.0) / 360
let maxHueAngle: Float = (hueAngle + hueRange/2.0) / 360
let size = 64
var cubeData = [Float](repeating: 0, count: size * size * size * 4)
var rgb: [Float] = [0, 0, 0]
var hsv: (h : Float, s : Float, v : Float)
var offset = 0
for z in 0 ..< size {
rgb[2] = Float(z) / Float(size) // blue value
for y in 0 ..< size {
rgb[1] = Float(y) / Float(size) // green value
for x in 0 ..< size {
rgb[0] = Float(x) / Float(size) // red value
hsv = RGBtoHSV(r: rgb[0], g: rgb[1], b: rgb[2])
// TODO: Check if hsv.s > 0.5 is really nesseccary
let alpha: Float = (hsv.h > minHueAngle && hsv.h < maxHueAngle && hsv.s > 0.5) ? 0 : 1.0
cubeData[offset] = rgb[0] * alpha
cubeData[offset + 1] = rgb[1] * alpha
cubeData[offset + 2] = rgb[2] * alpha
cubeData[offset + 3] = alpha
offset += 4
}
}
}
let b = cubeData.withUnsafeBufferPointer { Data(buffer: $0) }
let data = b as NSData
let colorCube = CIFilter(name: "CIColorCube", parameters: [
"inputCubeDimension": size,
"inputCubeData": data
])
return colorCube!
}
In my case, I'm trying to remove reds. Is there any other way to achieve this?
Hi dear friend as you seen in this link
.You must be use no between 330 to 360 degree for remove red color.
effectNode.filter = colorCubeFilterForChromaKey(hueAngle: 330)
I just started to learn Swift and I would like to code the game BubbleBreaker which I have already created in both Java and C# some years ago.
For this, I wanted to create a two-dimensional array of Bubble (which is derived from SKSpriteNode), however, when I am trying to populate the array, I always get an "index out of range error" at index [0][0]. Can somebody please help me?
class GameScene: SKScene {
//game settings
private var columns = 10
private var rows = 16
private var bubbleWidth = 0
private var bubbleHeight = 0
//bubble array
private var bubbles = [[Bubble]]()
override func didMove(to view: SKView) {
initializeGame()
}
private func initializeGame() {
self.anchorPoint = CGPoint(x: 0, y: 0)
//Optimize bubble size
bubbleWidth = Int(self.frame.width) / columns
bubbleHeight = Int(self.frame.height) / rows
if bubbleWidth < bubbleHeight {
bubbleHeight = bubbleWidth
}
else {
bubbleWidth = bubbleHeight
}
//Initialize bubble array
for i in 0 ... columns-1 {
for j in 0 ... rows-1 {
let size = CGSize(width: bubbleWidth, height: bubbleHeight)
let newBubble = Bubble(size: size)
newBubble.position = CGPoint(x: i*bubbleWidth, y: j*bubbleHeight)
bubbles[i][j] = newBubble // THIS IS WERE THE CODE BREAKS AT INDEX [0][0]
self.addChild(newBubble)
}
}
}
}
bubbles starts off empty. There's nothing at any index.
Update your loop to something like this:
//Initialize bubble array
for i in 0 ..< columns {
var innerArray = [Bubble]()
for j in 0 ..< rows {
let size = CGSize(width: bubbleWidth, height: bubbleHeight)
let newBubble = Bubble(size: size)
newBubble.position = CGPoint(x: i*bubbleWidth, y: j*bubbleHeight)
innertArray.append(newBubble)
self.addChild(newBubble)
}
bubbles.append(innerArray)
}
This builds up an array of arrays.
Instead of assigning new value as unexisting value, append new empty array of Bubble for every column and then append to this array newBubble for every row
for i in 0 ... columns-1 {
bubbles.append([Bubble]())
for j in 0 ... rows-1 {
let size = CGSize(width: bubbleWidth, height: bubbleHeight)
let newBubble = Bubble(size: size)
newBubble.position = CGPoint(x: i*bubbleWidth, y: j*bubbleHeight)
bubbles[i].append(newBubble)
self.addChild(newBubble)
}
}
Please take a look at my 2D-Array-Initialization. The code works.
class World(val size_x: Int = 256, val size_y: Int = 256) {
var worldTiles = Array(size_x, { Array(size_y, { WorldTile() }) })
fun generate() {
for( x in 0..size_x-1 ) {
for( y in 0..size_y-1 ) {
worldTiles[x][y] = WorldTile()
}
}
}
}
The problem is that it runs the initialization twice. Basically I want to instantiate the WorldTile-Object in the generate() function. So Line 3 shouldn't call "new WorldTile" there. How can I do that?
Also is that the proper Kotlin way of traversing a 2d-Array?
You can make worldTiles a lateinit property, and do all the initialization in the generate function:
class World(val size_x: Int = 256, val size_y: Int = 256) {
lateinit var worldTiles: Array<Array<WorldTile>>
fun generate() {
worldTiles = Array(size_x, {
Array(size_y, {
WorldTile()
})
})
}
}
If you try to access worldTiles before calling generate you will get an exception warning that it hasn't been initialized yet.
To initialise all to a fixed value:
// A 6x5 array of Int, all set to 0.
var m = Array(6) {Array(5) {0} }
To initialise with a lambda:
// a 6x5 Int array initialise i + j
var m = Array(6) { i -> Array(5) { j -> i + j } }
Another way: Here is an example of initialising a 2D array of Float numbers (3 by 6):
var a = Array(3) { FloatArray(6)} // define an 3x6 array of float numbers
for(i:Int in 0 until a.size) {
for(j : Int in 0 until a[i].size) {
a[i][j] = 0f // initialize with your value here.
}
}
val twoDimStringArray= arrayOf(
arrayOf("first","second"),
arrayOf("foo"),
arrayOf("bar","great kotlin")
)
for (i in twoDimStringArray){
for(j in i){
println(j)
}
}
first
second
foo
bar
great kotlin
A bit late but could help to somebody if is working with strings
//init 2d array with a fixed size:
var data2 = Array<Array<String>>(2) { arrayOf()}
// fill the 2d array
data2[0] = arrayOf("123","Freddy x","27")
data2[1] = arrayOf("124","Elon y","45")
cheers!
I am attempting to split an image into 10'000 smaller ones, by dividing the image into a grid of 100x100. When I run the code, I receive an Error_Bad_Instruction.
import Cocoa
import CoreImage
public class Image {
public var image: CGImage?
public func divide() -> [CGImage] {
var tiles: [CGImage] = []
for x in 0...100 {
for y in 0...100 {
let tile = image?.cropping(to: CGRect(x: (image?.width)!/x, y: (image?.height)!/y, width: (image?.width)! / 100, height: (image?.height)! / 100 ))
tiles.append(tile!)
}
}
return tiles
}
public init(image: CGImage) {
self.image = image
}
}
var img = Image(image: (NSImage(named: "aus-regions.jpg")?.cgImage(forProposedRect: nil, context: nil, hints: nil))!)
var a = img.divide()
There are some problems with the code that you posted:
forced wrapping the image
loops go including 100 - you just need 99. Or as a comment suggests: for x in 0..<100
you divide by 0 - in the first step
your algorithm, is not forming a grid.
I've updated to obtain a grid, using an image that I had on my computer, and with widths and heights just of 10, because it using 100 was too long.
import Cocoa
import CoreImage
let times = 10
public class Image {
public var image: CGImage?
public func divide() -> [CGImage] {
var tiles: [CGImage] = []
for x in 0..<times {
for y in 0..<times {
let tile = image?.cropping(to: CGRect(x: x * (image?.width)!/times, y: y * (image?.height)!/times, width: (image?.width)! / times, height: (image?.height)! / times ))
tiles.append(tile!)
}
}
return tiles
}
public init(image: CGImage) {
self.image = image
}
}
if let image = NSImage(named: "bg.jpg")?.cgImage(forProposedRect: nil, context: nil, hints: nil) {
var img = Image(image: image)
var a = img.divide()
}
Basically, I have an array that is shuffled. The array is a deck of cards as such:
var rank = ["A","2","3","4","5","6","7","8","9","10","J","Q","K"]
var suit = ["♠", "♥","♦","♣"]
var deck = [String]()
I have a for Loop to create the deck with
for t in suit {
for r in rank {
deck.append("\(r)\(t)")
}
}
I then in a function call an extension which I created to shuffle the deck. (This brings me back 52 cards assorted randomly)
deck.shuffle()
The only thing is while results are random, I don't want cards to repeat. For example, if the result is a 2♠, I wouldn't want 2♥, 2♦, 2♣ following in the printed list.
Any help is appreciated! Thanks!
I think that the best way to proceed is to use a modified Knuth shuffle. The code below is a complete example. Just run it in a shell with swiftc -o customshuffle customshuffle.swift && ./customshuffle after saving the content in customshuffle.swift.
import Foundation
let decksize = 52
let rankStrings = ["A","2","3","4","5","6","7","8","9","10","J","Q","K"]
let suitStrings = ["♠", "♥","♦","♣"]
struct card : Hashable, Equatable, CustomStringConvertible {
var rank: Int //1,2...,11,12,13
var suit: Int // 1,2,3,4
var hashValue: Int {
return rank + suit
}
static func == (lhs: card, rhs: card) -> Bool {
return lhs.rank == rhs.rank && lhs.suit == rhs.suit
}
var description: String {
return rankStrings[self.rank - 1] + suitStrings[self.suit - 1]
}
}
// seems like Swift still lacks a portable random number generator
func portablerand(_ max: Int)->Int {
#if os(Linux)
return Int(random() % (max + 1)) // biased but I am in a hurry
#else
return Int(arc4random_uniform(UInt32(max)))
#endif
}
// we populate a data structure where the
// cards are partitioned by rank and then suit (this is not essential)
var deck = [[card]]()
for i in 1...13 {
var thisset = [card]()
for j in 1...4 {
thisset.append(card(rank:i,suit:j))
}
deck.append(thisset)
}
// we write answer in "answer"
var answer = [card]()
// we pick a card at random, first card is special
var rnd = portablerand(decksize)
answer.append(deck[rnd / 4].remove(at: rnd % 4))
while answer.count < decksize {
// no matter what, we do not want to repeat this rank
let lastrank = answer.last!.rank
var myindices = [Int](deck.indices)
myindices.remove(at: lastrank - 1)
var totalchoice = 0
var maxbag = -1
for i in myindices {
totalchoice = totalchoice + deck[i].count
if maxbag == -1 || deck[i].count > deck[maxbag].count {
maxbag = i
}
}
if 2 * deck[maxbag].count >= totalchoice {
// we have to pick from maxbag
rnd = portablerand(deck[maxbag].count)
answer.append(deck[maxbag].remove(at: rnd))
} else {
// any bag will do
rnd = portablerand(totalchoice)
for i in myindices {
if rnd >= deck[i].count {
rnd = rnd - deck[i].count
} else {
answer.append(deck[i].remove(at: rnd))
break
}
}
}
}
for card in answer {
print(card)
}
This can be computed fast and it is reasonably fair, but not unbiased sadly. I suspect it might be hard to generate a "fair shuffle" with your constraint that runs fast.