How tom Show 3D pie-chart in swift 4 in my app - ios

I am trying to show a 3D pie-chart in my app in swift 4.
but can't find any solution.does anyone help me or give me any suggestion please??

private func createPieChart() -> SCNNode {
let aNode = SCNNode()
var total:Float = 0.0
//let numRows = data.numberOfRows()
let numColumns = data.numberOfColums()
let i = 0
for j in 0 ..< numColumns {
let val = data.valueForIndexPath(row:i, column: j)
total = total + val
}
var startDeg:Float = 0.0
var startRad:Float = 0.0
for j in 0 ..< numColumns {
let val = data.valueForIndexPath(row:i, column: j)
let pct = val*360.0/total
startRad = Float(startDeg) * Float(M_PI) / Float(180.0)
let endDeg = startDeg + pct - 1.0
let endRad:Float = Float(endDeg) * Float(M_PI) / Float(180.0)
let circlePath = UIBezierPath()
circlePath.move(to: CGPoint.zero)
circlePath.addArc(withCenter: CGPoint.zero, radius: 20.0, startAngle:CGFloat(startRad), endAngle: CGFloat(endRad), clockwise: true)
startDeg = endDeg + 1
let node = SCNNode(geometry: SCNShape(path:circlePath, extrusionDepth: 5.0))
node.geometry?.firstMaterial?.diffuse.contents = data.colorForIndexPath(row: i, column: j)
aNode.addChildNode(node)
}
return aNode
}

Related

Find the Bounding Box of Submesh in iOS

I am drawing a 3D model as below from a obj file. I need to find the Bounding box for each submesh of that obj file.
let assetURL = Bundle.main.url(forResource: "train", withExtension: "obj")!
let allocator = MTKMeshBufferAllocator(device: device)
let asset = MDLAsset(url: assetURL, vertexDescriptor: vertexDescriptor, bufferAllocator: meshAllocator)
let mdlMesh = asset.object(at: 0) as! MDLMesh
mesh = try! MTKMesh(mesh: mdlMesh, device: device)
for submesh in mesh.submeshes {
//I need to find the bounding box for each Submesh
}
How can I achieve that in iOS.
Here's a function that takes an MTKMesh and produces an array of MDLAxisAlignedBoundingBoxes in model space:
enum BoundingBoxError : Error {
case invalidIndexType(String)
}
func boundingBoxesForSubmeshes(of mtkMesh: MTKMesh, positionAttributeData: MDLVertexAttributeData) throws -> [MDLAxisAlignedBoundingBox]
{
struct VertexPosition {
var x, y, z: Float
}
var boundingBoxes = [MDLAxisAlignedBoundingBox]()
var minX = Float.greatestFiniteMagnitude
var minY = Float.greatestFiniteMagnitude
var minZ = Float.greatestFiniteMagnitude
var maxX = -Float.greatestFiniteMagnitude
var maxY = -Float.greatestFiniteMagnitude
var maxZ = -Float.greatestFiniteMagnitude
let positionsPtr = positionAttributeData.dataStart
for submesh in mtkMesh.submeshes {
let indexBuffer = submesh.indexBuffer
let mtlIndexBuffer = indexBuffer.buffer
let submeshIndicesRaw = mtlIndexBuffer.contents().advanced(by: indexBuffer.offset)
if submesh.indexType != .uint32 {
throw BoundingBoxError.invalidIndexType("Expected 32-bit indices")
}
let submeshIndicesPtr = submeshIndicesRaw.bindMemory(to: UInt32.self,
capacity: submesh.indexCount)
let submeshIndices = UnsafeMutableBufferPointer<UInt32>(start: submeshIndicesPtr,
count:submesh.indexCount)
for index in submeshIndices {
let positionPtr = positionsPtr.advanced(by: Int(index) * positionAttributeData.stride)
let position = positionPtr.assumingMemoryBound(to: VertexPosition.self).pointee
if position.x < minX { minX = position.x }
if position.y < minY { minY = position.y }
if position.z < minZ { minZ = position.z }
if position.x > maxX { maxX = position.x }
if position.y > maxY { maxY = position.y }
if position.z > maxZ { maxZ = position.z }
}
let min = SIMD3<Float>(x: minX, y: minY, z: minZ)
let max = SIMD3<Float>(x: maxX, y: maxY, z: maxZ)
let box = MDLAxisAlignedBoundingBox(maxBounds: max, minBounds: min)
boundingBoxes.append(box)
}
return boundingBoxes
}
Note that this function expects the submesh to have 32-bit indices, though it could be adapted to support 16-bit indices as well.
To drive it, you'll also need to supply an MDLVertexAttributeData object that points to the vertex data in the containing mesh. Here's how to do that:
let mesh = try! MTKMesh(mesh: mdlMesh, device: device)
let positionAttrData = mdlMesh.vertexAttributeData(forAttributeNamed: MDLVertexAttributePosition, as: .float3)!
let boundingBoxes = try? boundingBoxesForSubmeshes(of: mesh, positionAttributeData: positionAttrData)
I haven't tested this code thoroughly, but it seems to produce sane results on my limited set of test cases. Visualizing the boxes with a debug mesh should immediately show whether or not they're correct.

Different results and codes for the discrete cosine transform... what is going on?

I need to do a Discreet Cosine Transform of the following data:
0.6191342,0.6197224,0.61898607,0.61912596,0.6190106,0.61988443,0.61900085,0.6187835,0.6180295,0.61910814,0.6146555,0.6182434,0.6189235,0.61222005,0.6207976,0.6218684,0.62007576,0.6216523,0.6215335,0.62065303,0.6205161,0.61968786,0.619246,0.6213837,0.62122154,0.6192542,0.61824924,0.61987126,0.62156975,0.62128264,0.6205598,0.62057704,0.62053716,0.62275934,0.6218448,0.6203091,0.6178272,0.6140544,0.6213627,0.62143743,0.6132956,0.61910033,0.61519396,0.62216187,0.6215059,0.6197418,0.615724,0.62262917,0.62247676,0.62028235,0.6186407,0.619341,0.6152448,0.62161505,0.61356294,0.6133514,0.618384,0.6184519,0.6158993,0.6210517,0.61071134,0.62111616,0.61093444,0.62230366,0.6216592,0.61184555,0.61515874,0.6136047,0.6233515,0.618276,0.6159197,0.61444646,0.6185363,0.6162487,0.61572075,0.6194457,0.61314666,0.61829245,0.62141377,0.62105316,0.6124673,0.6179071,0.6186554,0.62159,0.61449164,0.61788505,0.6064126,0.6184563,0.6143939,0.6169126,0.61230534,0.6193385,0.6139966,0.6149371,0.6178339,0.61179554,0.6135024,0.61419034,0.614619,0.6137465,0.6185665,0.6185372,0.6163691,0.6195464,0.6170328,0.61263216,0.6161196,0.6184589,0.622137,0.61809236,0.61836344,0.61896133,0.6169496,0.6195432,0.6197563,0.61895114,0.61758405,0.61847824,0.61592484,0.6179055,0.61649424,0.61602193,0.6174835,0.61842364,0.60891753,0.61700743,0.6159329,0.61829287,0.6166717,0.6159072,0.6157982,0.6081088,0.6191729,0.61839896,0.615376,0.6154309,0.6119571,0.61734617,0.6171004,0.6178271,0.6169227,0.6172922,0.61745894,0.6195544,0.6103485,0.6142039,0.6166354,0.61975944,0.6184104,0.6177316,0.6150697,0.61001426,0.6108277,0.617212,0.6106007,0.61446583,0.61284953,0.6152104,0.6181612,0.61701053,0.6148785,0.61547005,0.62181646,0.618621,0.6161165,0.616407,0.6115453,0.6172732,0.61757433,0.61611485,0.61767805,0.61765575,0.61649793,0.6184486,0.6195102,0.61967367,0.6210996,0.61727804,0.6189702,0.6188129,0.6160338,0.6205609,0.6199804,0.6170756,0.6182058,0.61902076,0.62221605,0.6212938,0.61759907,0.6170265,0.6073142,0.6191233,0.61933994,0.61591357,0.6168009,0.6149173,0.6155775,0.6203353,0.6168877,0.61844844,0.60965574,0.61050487,0.62154305,0.62103915,0.6164665,0.6161686,0.60936993,0.614351,0.6204919,0.61622816,0.61612433,0.61211497,0.61347705,0.6192275,0.6165203,0.6156739,0.61536443,0.6136969,0.6195982,0.6201504,0.61684716,0.6125972,0.61233103,0.6179449,0.6163167,0.6089562,0.60863984,0.61114866,0.6104453,0.6166812,0.61086583,0.6118273,0.6211713,0.6160922,0.60824126,0.60837793,0.61538464,0.6222241,0.60950315,0.61592793,0.60851187,0.613283,0.61787575,0.6204593,0.6155273,0.6085147,0.6164997,0.61334276,0.61671215,0.6086348,0.6089769,0.61735654,0.6203436,0.60964227,0.6184011,0.6144072
If I use the Accelerate functions provided by Apple, I get these results:
2.669825,0.23372388,0.034602005,0.14609262,-0.05658116,0.028039198,-0.019894773,-0.12209733,0.022227166,0.0051003816,-0.042596065,-0.04589792,0.01035949,-0.019523097,0.077776365,0.0030713473,-0.078441024,-0.00070093106,0.01997262,0.06481835,-0.004874494,0.023854036,0.029294237,0.011619994,-0.0012118752,0.010400612,0.023407647,-0.05563956,0.038198948,-0.01233741,0.009424317,0.039608873,0.05801,0.028565174,-0.012889689,0.021731874,-0.026493106,-0.048108768,0.0045189788,-0.032068893,-0.017894993,-0.025662154,0.010751593,-0.07121442,0.06277961,0.0022988198,-0.018414639,-0.021932043,-0.020916257,-0.01747331,0.006716689,0.023302665,0.0068657864,-0.019596279,-0.043121584,0.04483221,-0.00012186449,-0.012160094,0.011104634,-0.015813472,0.023498433,0.02872037,0.014691476,0.015423553,-0.032783255,0.028947365,0.03251956,-0.016012289,-0.018248938,0.026564144,-0.034706548,0.012790314,0.002194486,0.04613065,-0.05747463,0.010088965,0.017059956,-0.04142371,-0.040067486,0.0029621175,0.07121314,-0.0064264582,-0.0064690933,-0.040944442,-0.0025974065,0.0075896196,-0.006084161,-0.027271878,0.056449506,-0.01756429,0.020225035,0.05740238,-0.07323427,0.091452986,-0.06606907,-0.00599443,0.03895919,0.0029399507,0.0050259903,-0.017262679,-0.052305933,0.0132182,-0.14926372,0.12026562,0.06996072,0.050748315,0.020096999,-0.017148953,0.006768549,-0.07308701,0.045742266,-0.055744015,0.034470245,-0.06591675,0.012785097,-0.045998022,0.028786233,-0.0006729504,0.026651034,0.016280383,-0.016419016,-0.0235405,-0.011106867,0.0060093636,-0.026253335,-0.020966358,0.049879722,-0.019093664,0.055243053,0.008216016,0.039922368,-0.05096092,0.010148679,-0.011200655,0.044212196,-0.012730424,0.027963173,-0.0050371652,0.0006729523,-0.02703674,-0.040479846,0.0032800399,0.019346198,0.03412081,-0.0062747486,-0.018566221,-0.011666842,0.02345107,-0.07089561,0.023972765,-0.0076217707,0.00794466,-0.008454496,-0.051500462,0.007845432,-0.046568125,-0.018137766,0.026703745,0.035737798,-0.061839998,-0.00884305,0.009104564,0.052314416,0.028979728,-0.017012393,-0.019422699,-0.049617197,0.03505949,0.005899897,0.031378012,0.02203784,0.05013973,-0.014152746,0.029270608,0.049914937,0.01226829,-0.038096413,0.012367716,-0.04856258,0.008609608,-0.014275378,-0.00032820972,0.003259441,0.04173329,0.0026449636,0.020232702,-0.058400147,0.006697319,-0.083465755,0.023861019,-0.019418886,-0.034204446,0.057170536,-0.03352673,-0.020436082,-0.024796713,-0.054371275,0.055950172,-0.01681035,0.018895034,0.042727623,0.040553555,-0.049501,0.003925497,-0.034148764,-0.00027683005,-0.054910377,0.03833572,0.053599093,0.02369698,-0.0021882567,0.04318303,0.0055106683,-0.026357781,-0.0022721058,-0.036762282,0.06495822,0.030521873,0.003908515,-0.052683424,-0.00785333,-0.0245375,-0.006546188,0.03067175,0.046067707,0.0047659995,-0.03191337,0.010508363,-0.0308632,-0.016877536,-0.05901345,0.0061260397,0.008024132,0.052667245,-0.026830386,0.021430418,-0.044398945,-0.02600174,-0.032572,0.06329122,0.032917332,0.0284806,-0.074899085,-0.025770163,-0.015752867,0.0030335134,0.04120659,0.0026583495,-0.005403653,0.009906204,0.029109228,0.015893774,0.0023716427,-0.02794688,-0.033177476,-0.08380169
If I use a code I call dctA I get this:
0.16686402,-0.235977,0.23596367,-0.23594144,0.23591036,-0.23587029,0.23582156,-0.23576365,0.23569722,-0.23562174,0.23553737,-0.2354442,0.23534207,-0.2352311,0.2351113,-0.23498271,0.23484512,-0.23469894,0.23454358,-0.2343797,0.2342069,-0.23402523,0.23383485,-0.23363559,0.2334273,-0.23321046,0.2329848,-0.23275039,0.23250724,-0.23225537,0.23199482,-0.2317253,0.23144716,-0.23116058,0.23086505,-0.23056087,0.23024791,-0.22992653,0.22959618,-0.22925732,0.22890992,-0.22855341,0.22818917,-0.22781523,0.22743407,-0.22704314,0.22664468,-0.22623657,0.22582,-0.225396,0.22496259,-0.22452155,0.22407113,-0.22361335,0.22314598,-0.22267129,0.22218716,-0.22169586,0.2211951,-0.22068696,0.22016953,-0.21964486,0.21911088,-0.21856976,0.21801907,-0.21746023,0.21689478,-0.21631947,0.21573758,-0.21514617,0.2145479,-0.2139403,0.2133261,-0.21270223,0.212072,-0.21143214,0.2107861,-0.21013027,0.20946832,-0.20879678,0.20811911,-0.20743181,0.20673671,-0.2060339,0.2053268,-0.20460844,0.20388247,-0.20314853,0.20241094,-0.20166187,0.20090508,-0.20014101,0.19937299,-0.19859369,0.19780688,-0.19701274,0.19621103,-0.19540597,0.19458961,-0.19376592,0.19293484,-0.19210072,0.19125515,-0.19040233,0.18954237,-0.18867959,0.18780532,-0.18692416,0.18603577,-0.1851449,0.18424252,-0.1833334,0.18241717,-0.1814941,0.18056883,-0.17963219,0.17868869,-0.1777385,0.17678645,-0.17582284,0.17485264,-0.17387584,0.1728974,-0.17190763,0.17091122,-0.1699084,0.16890429,-0.16788879,0.16686694,-0.16583884,0.16480431,-0.16376887,0.16272213,-0.16166915,0.16061012,-0.15955035,0.15847927,-0.15740223,0.15631929,-0.15523578,0.15414095,-0.15304045,0.15193413,-0.15082765,0.14970991,-0.14858656,0.1474576,-0.14632308,0.14518869,-0.14404319,0.14289224,-0.14173594,0.14057998,-0.13941304,0.13824077,-0.13706335,0.13588662,-0.1346989,0.13350609,-0.13230827,0.13111141,-0.12990372,0.12869103,-0.12747958,0.12625119,-0.1250302,0.12379233,-0.122562,0.121327065,-0.120075285,0.118831374,-0.11758294,0.11631756,-0.11506039,0.11378633,-0.112520546,0.11125048,-0.10996368,0.10868541,-0.10739021,0.10610382,-0.104813375,0.10350613,-0.102208,0.100905985,-0.09958719,0.098277606,-0.096951276,0.09563441,-0.09431398,0.092976734,-0.09164931,0.090305135,-0.088970825,0.087633155,-0.086278856,0.08493474,-0.08358737,0.08222347,-0.0808699,0.079499744,-0.07814017,0.07677769,-0.07539867,0.07403045,-0.07265948,0.07127206,-0.069895685,0.0685029,-0.06712131,0.06573725,-0.06433683,0.062947854,-0.061542634,0.06014901,-0.05875311,0.057341076,-0.055940807,0.054538473,-0.053120058,0.05171367,-0.05029129,0.048881073,-0.047469016,0.046041086,-0.044625536,0.043194164,-0.041775327,0.0403549,-0.038918786,0.0374954,-0.03607061,0.03463024,-0.033202793,0.031759836,-0.030329958,0.028898928,-0.027452547,0.026019417,-0.024585323,0.02313597,-0.021700067,0.020249018,-0.018811548,0.017373376,-0.015920186,0.014480768,-0.013026423,0.0115859695,-0.0101450775,0.00868942,-0.0072478293,0.0058059655,-0.0043494827,0.0029072375,-0.0014504795
and if I use another code I have found on the web, that I call dctB I get this:
0.23598135,0.0065520015,-0.0014035295,-0.0014900116,-0.0029997544,-0.0022787564,0.003723558,-0.003108655,-0.0012933733,-0.0007105355,0.0012699091,-0.00060556503,0.0053185527,0.00076327357,-0.0011331664,0.005722867,0.0034567474,-0.0011424342,-0.0013203556,0.0021249577,-0.0029971765,0.0006293817,0.0019937858,0.0026412704,0.00016487329,-0.003959481,0.00039281833,-0.0024429162,0.00060916966,-0.0019161169,-0.006625204,-0.002263753,0.00040166255,-0.0013965253,-0.00019885821,-0.010229679,0.0015206567,-0.0053624627,0.00058637373,0.0070882766,-0.0044516595,0.0010087036,-0.0064169616,0.0043392666,0.0012746729,0.0014619434,-0.0050648195,0.0009482073,0.004468296,-0.0015502489,-0.0043041282,-0.001236145,0.0048462045,-0.003547573,0.0035744759,0.0021012123,0.0039755865,0.0017270996,-0.0047634826,0.0021218802,0.003715937,-0.0038134162,-0.0031784503,0.0021606751,0.0063801087,-6.5251596e-05,-0.004479158,-0.0052841934,0.0056381524,0.0003858073,-0.00277002,0.001508747,0.005996452,-0.0019169269,0.001555898,0.00014130188,0.005808804,0.0037767508,-0.0026520337,-0.0018158474,0.0033173792,0.0046277773,-0.0006036768,-0.0019087599,9.9361154e-05,0.004506388,-0.0044565895,0.00051484356,-0.0026925507,0.005224032,8.564865e-05,-0.0057873107,-0.000118939184,-0.0065063527,0.004078492,0.0003850522,-0.0038591337,0.0016885462,-0.0028994652,0.00063551,0.0018036738,-0.0020673752,-1.50109045e-05,0.0007685168,-0.0028343478,0.003231319,0.0062061716,0.0032275403,-0.002344687,0.000663079,-0.0016223937,-0.0045130113,0.0058470825,0.00283345,-0.0020404255,-9.103818e-05,0.004184909,-0.003951648,-0.00038761974,0.0010700208,-0.0066716103,-0.00018829755,0.0036042533,-0.0043730726,-0.002380092,0.0013307306,-0.0021570993,0.007163353,0.16732568,0.0021171984,0.00011411852,-0.00347561,-0.0018730971,0.0011592627,0.0017720436,-0.0042686476,0.004867761,-0.002120747,0.002259214,0.003109498,0.0034014524,0.0012342912,0.00042545033,0.005238078,-0.0009351839,0.0028766692,-0.0002561589,0.0023975722,-0.0019213242,-0.0023478842,-0.0033766865,0.0005857277,0.0030684788,-0.006383024,0.00048669687,-0.0014512719,-0.0009451752,-0.0033242197,-0.006483069,-0.004888436,0.00435442,-0.0022291946,-0.0043107485,-0.007959526,0.0022944517,-0.0017021666,0.000734793,0.0049511404,-0.003661971,0.00094925304,-0.004634777,0.0016841891,0.0016499859,0.003999946,-0.0065253885,-0.0033514274,0.003085088,-0.0003703781,-0.003465078,-0.0054242075,0.0009584457,-0.005197831,0.003603162,0.0048823943,-0.00041171763,0.0009989656,-0.0040209224,0.002628903,-0.0003624089,-0.0002924401,-3.2498552e-05,0.0031572247,0.0026128257,-0.0022803256,-0.0030580086,-0.00357484,0.0042991657,-0.0015585661,0.00086751115,0.0004323435,0.0045290007,-0.0048501627,-0.001418146,0.00370478,0.003376496,0.006685608,0.00055006717,-0.0011108073,0.00024791225,0.0055819694,0.0041101393,-0.0041453117,-0.0011638473,0.0020769653,-8.08032e-06,-0.0002288826,0.0006749544,0.00035142386,-0.00043356852,-0.0029805794,-0.0017968996,0.0010227,0.006042389,0.0017817094,-0.0056505343,0.004619073,0.0023046366,0.0027151196,0.0020018944,-0.00041239324,-0.00031199362,0.0050316383,-0.0041035055,0.001887646,0.0069080763,0.0039198315,-0.0003352705,-0.0012968663,-0.0009449865,-0.0052614617,0.004834936,-0.0014728566,-0.0017496345,-0.0008812858,0.00056978094,-0.005053855,-0.0017934664,0.0021964775,-0.008228115,0.0029420764,0.0012297969,-0.0038868873,-0.0003670447,0.0032279065,-0.0016167451,0.0036267326
These are the 3 codes in order:
let DCTSetupForward = vDSP_DCT_CreateSetup(nil,
vDSP_Length(numberSamples),
vDSP_DCT_Type.II)
var output = Array<Float>(repeating:0.0,
count: numberSamples)
vDSP_DCT_Execute(DCTSetupForward!, data, &output)
func dctA (_ data:[Float] = []) -> Array<Float> {
let numberSamples = data.count
var c = [Float](repeating: 0,
count: numberSamples)
for i in 0..< numberSamples {
var sum : Float = 0
let s : Float = (i == 0) ? sqrt(0.5) : 1
for j in 0..< numberSamples {
sum = sum + s * data[j] * cos(Float.pi * (numberSamples + 0.5) * Float(i) / numberSamples)
}
c[i] = sum * sqrt(2.0 / numberSamples)
}
return c;
}
func dctB (_ data:[Float] = []) -> Array<Float> {
var angle : Float
var c :[Float] = []
let numberSamples = data.count
for i in 0..<numberSamples {
c.append(0)
for j in 0..< numberSamples {
let fk = Float(2*j + 1)
let y = Float.pi * Float(i) * fk
let fky = fk * y
let x = Float(2 * numberSamples)
angle = fky / x
c[i] = c[i] + cos ( angle ) * data[j];
}
c[i] = c[i] * sqrt (2.0/Float(numberSamples));
}
return c;
}
I have noticed the difference in the two last codes. So, I have 3 questions:
Why am I having 3 different results for the DCT of this data?
Can someone with mathlab check which is the right one?
why the difference in the last two codes?
Searching through Wikipedia and the formula of the above are different for typeII.
If you following the corrected one below, the error mainly comes from rounding during multiplying and summation.
let DCTSetupForward = vDSP_DCT_CreateSetup(nil,
vDSP_Length(numberSamples),
vDSP_DCT_Type.II)
var output = Array<Float>(repeating:0.0,
count: numberSamples)
vDSP_DCT_Execute(DCTSetupForward!, data, &output)
print(output)
func dctA (_ data:[Float] = []) -> Array<Float> {
let numberSample = data.count
var c = [Float](repeating: 0,
count: numberSample)
for i in 0..<numberSample {
var sum : Float = 0
let s : Float = (i == 0) ? 1 : 1
for j in 0..<numberSample {
sum = sum + s * data[j] * cos(Float.pi * (Float(j) + 0.5) * Float(i) / Float(numberSample))
}
c[i] = sum
}
return c;
}
func dctB (_ data:[Float] = []) -> Array<Float> {
var angle : Float
var c :[Float] = []
let numberSampl = data.count
for i in 0..<numberSampl {
c.append(0)
for j in 0..<numberSampl {
let fk = Float(2*j + 1)
let y = Float.pi * Float(i) * fk
// let fky = fk * y
let x = Float(2 * numberSampl)
angle = y / x
c[i] = c[i] + cos ( angle ) * data[j];
}
}
return c;
}

How to draw an arc on Google Maps in iOS?

How to draw an arc between two coordinate points in Google Maps like in this image and same like facebook post in iOS ?
Before using the below function, don't forget to import GoogleMaps
Credits: xomena
func drawArcPolyline(startLocation: CLLocationCoordinate2D?, endLocation: CLLocationCoordinate2D?) {
if let startLocation = startLocation, let endLocation = endLocation {
//swap the startLocation & endLocation if you want to reverse the direction of polyline arc formed.
let mapView = GMSMapView()
let path = GMSMutablePath()
path.add(startLocation)
path.add(endLocation)
// Curve Line
let k: Double = 0.2 //try between 0.5 to 0.2 for better results that suits you
let d = GMSGeometryDistance(startLocation, endLocation)
let h = GMSGeometryHeading(startLocation, endLocation)
//Midpoint position
let p = GMSGeometryOffset(startLocation, d * 0.5, h)
//Apply some mathematics to calculate position of the circle center
let x = (1 - k * k) * d * 0.5 / (2 * k)
let r = (1 + k * k) * d * 0.5 / (2 * k)
let c = GMSGeometryOffset(p, x, h + 90.0)
//Polyline options
//Calculate heading between circle center and two points
let h1 = GMSGeometryHeading(c, startLocation)
let h2 = GMSGeometryHeading(c, endLocation)
//Calculate positions of points on circle border and add them to polyline options
let numpoints = 100.0
let step = ((h2 - h1) / Double(numpoints))
for i in stride(from: 0.0, to: numpoints, by: 1) {
let pi = GMSGeometryOffset(c, r, h1 + i * step)
path.add(pi)
}
//Draw polyline
let polyline = GMSPolyline(path: path)
polyline.map = mapView // Assign GMSMapView as map
polyline.strokeWidth = 3.0
let styles = [GMSStrokeStyle.solidColor(UIColor.black), GMSStrokeStyle.solidColor(UIColor.clear)]
let lengths = [20, 20] // Play with this for dotted line
polyline.spans = GMSStyleSpans(polyline.path!, styles, lengths as [NSNumber], .rhumb)
let bounds = GMSCoordinateBounds(coordinate: startLocation, coordinate: endLocation)
let insets = UIEdgeInsets(top: 20, left: 20, bottom: 20, right: 20)
let camera = mapView.camera(for: bounds, insets: insets)!
mapView.animate(to: camera)
}
}
I used Bezier quadratic equation to draw curved lines. You can have a look on to the implementation. Here is the sample code.
func bezierPath(from startLocation: CLLocationCoordinate2D, to endLocation: CLLocationCoordinate2D) -> GMSMutablePath {
let distance = GMSGeometryDistance(startLocation, endLocation)
let midPoint = GMSGeometryInterpolate(startLocation, endLocation, 0.5)
let midToStartLocHeading = GMSGeometryHeading(midPoint, startLocation)
let controlPointAngle = 360.0 - (90.0 - midToStartLocHeading)
let controlPoint = GMSGeometryOffset(midPoint, distance / 2.0 , controlPointAngle)
let path = GMSMutablePath()
let stepper = 0.05
let range = stride(from: 0.0, through: 1.0, by: stepper)// t = [0,1]
func calculatePoint(when t: Double) -> CLLocationCoordinate2D {
let t1 = (1.0 - t)
let latitude = t1 * t1 * startLocation.latitude + 2 * t1 * t * controlPoint.latitude + t * t * endLocation.latitude
let longitude = t1 * t1 * startLocation.longitude + 2 * t1 * t * controlPoint.longitude + t * t * endLocation.longitude
let point = CLLocationCoordinate2D(latitude: latitude, longitude: longitude)
return point
}
range.map { calculatePoint(when: $0) }.forEach { path.add($0) }
return path
}
None of the answers mentioned is a full proof solution. For a few locations, it draws a circle instead of a polyline.
To resolve this we will calculate bearing(degrees clockwise from true north) and if it is less than zero, swap the start and end location.
func createArc(
startLocation: CLLocationCoordinate2D,
endLocation: CLLocationCoordinate2D) -> GMSPolyline {
var start = startLocation
var end = endLocation
if start.bearing(to: end) < 0.0 {
start = endLocation
end = startLocation
}
let angle = start.bearing(to: end) * Double.pi / 180.0
let k = abs(0.3 * sin(angle))
let path = GMSMutablePath()
let d = GMSGeometryDistance(start, end)
let h = GMSGeometryHeading(start, end)
let p = GMSGeometryOffset(start, d * 0.5, h)
let x = (1 - k * k) * d * 0.5 / (2 * k)
let r = (1 + k * k) * d * 0.5 / (2 * k)
let c = GMSGeometryOffset(p, x, h + 90.0)
var h1 = GMSGeometryHeading(c, start)
var h2 = GMSGeometryHeading(c, end)
if (h1 > 180) {
h1 = h1 - 360
}
if (h2 > 180) {
h2 = h2 - 360
}
let numpoints = 100.0
let step = ((h2 - h1) / Double(numpoints))
for i in stride(from: 0.0, to: numpoints, by: 1) {
let pi = GMSGeometryOffset(c, r, h1 + i * step)
path.add(pi)
}
path.add(end)
let polyline = GMSPolyline(path: path)
polyline.strokeWidth = 3.0
polyline.spans = GMSStyleSpans(
polyline.path!,
[GMSStrokeStyle.solidColor(UIColor(hex: "#2962ff"))],
[20, 20], .rhumb
)
return polyline
}
The bearing is the direction in which a vertical line on the map points, measured in degrees clockwise from north.
func bearing(to point: CLLocationCoordinate2D) -> Double {
func degreesToRadians(_ degrees: Double) -> Double { return degrees * Double.pi / 180.0 }
func radiansToDegrees(_ radians: Double) -> Double { return radians * 180.0 / Double.pi }
let lat1 = degreesToRadians(latitude)
let lon1 = degreesToRadians(longitude)
let lat2 = degreesToRadians(point.latitude);
let lon2 = degreesToRadians(point.longitude);
let dLon = lon2 - lon1;
let y = sin(dLon) * cos(lat2);
let x = cos(lat1) * sin(lat2) - sin(lat1) * cos(lat2) * cos(dLon);
let radiansBearing = atan2(y, x);
return radiansToDegrees(radiansBearing)
}
The answer above does not handle all the corner cases, here is one that draws the arcs nicely:
func drawArcPolyline(startLocation: CLLocationCoordinate2D?, endLocation: CLLocationCoordinate2D?) {
if let _ = startLocation, let _ = endLocation {
//swap the startLocation & endLocation if you want to reverse the direction of polyline arc formed.
var start = startLocation!
var end = endLocation!
var gradientColors = GMSStrokeStyle.gradient(
from: UIColor(red: 11.0/255, green: 211.0/255, blue: 200.0/255, alpha: 1),
to: UIColor(red: 0/255, green: 44.0/255, blue: 66.0/255, alpha: 1))
if startLocation!.heading(to: endLocation!) < 0.0 {
// need to reverse the start and end, and reverse the color
start = endLocation!
end = startLocation!
gradientColors = GMSStrokeStyle.gradient(
from: UIColor(red: 0/255, green: 44.0/255, blue: 66.0/255, alpha: 1),
to: UIColor(red: 11.0/255, green: 211.0/255, blue: 200.0/255, alpha: 1))
}
let path = GMSMutablePath()
// Curve Line
let k = abs(0.3 * sin((start.heading(to: end)).degreesToRadians)) // was 0.3
let d = GMSGeometryDistance(start, end)
let h = GMSGeometryHeading(start, end)
//Midpoint position
let p = GMSGeometryOffset(start, d * 0.5, h)
//Apply some mathematics to calculate position of the circle center
let x = (1-k*k)*d*0.5/(2*k);
let r = (1+k*k)*d*0.5/(2*k);
let c = GMSGeometryOffset(p, x, h + 90.0)
//Polyline options
//Calculate heading between circle center and two points
var h1 = GMSGeometryHeading(c, start)
var h2 = GMSGeometryHeading(c, end)
if(h1>180){
h1 = h1 - 360
}
if(h2>180){
h2 = h2 - 360
}
//Calculate positions of points on circle border and add them to polyline options
let numpoints = 100.0
let step = (h2 - h1) / numpoints
for i in stride(from: 0.0, to: numpoints, by: 1) {
let pi = GMSGeometryOffset(c, r, h1 + i * step)
path.add(pi)
}
path.add(end)
//Draw polyline
let polyline = GMSPolyline(path: path)
polyline.map = mapView // Assign GMSMapView as map
polyline.strokeWidth = 5.0
polyline.spans = [GMSStyleSpan(style: gradientColors)]
}
}
Objective-C version #Rouny answer
- (void)DrawCurvedPolylineOnMapFrom:(CLLocationCoordinate2D)startLocation To:(CLLocationCoordinate2D)endLocation
{
GMSMutablePath * path = [[GMSMutablePath alloc]init];
[path addCoordinate:startLocation];
[path addCoordinate:endLocation];
// Curve Line
double k = 0.2; //try between 0.5 to 0.2 for better results that suits you
CLLocationDistance d = GMSGeometryDistance(startLocation, endLocation);
float h = GMSGeometryHeading(startLocation , endLocation);
//Midpoint position
CLLocationCoordinate2D p = GMSGeometryOffset(startLocation, d * 0.5, h);
//Apply some mathematics to calculate position of the circle center
float x = (1-k*k)*d*0.5/(2*k);
float r = (1+k*k)*d*0.5/(2*k);
CLLocationCoordinate2D c = GMSGeometryOffset(p, x, h + -90.0);
//Polyline options
//Calculate heading between circle center and two points
float h1 = GMSGeometryHeading(c, startLocation);
float h2 = GMSGeometryHeading(c, endLocation);
//Calculate positions of points on circle border and add them to polyline options
float numpoints = 100;
float step = ((h2 - h1) / numpoints);
for (int i = 0; i < numpoints; i++) {
CLLocationCoordinate2D pi = GMSGeometryOffset(c, r, h1 + i * step);
[path addCoordinate:pi];
}
//Draw polyline
GMSPolyline * polyline = [GMSPolyline polylineWithPath:path];
polyline.map = mapView;
polyline.strokeWidth = 3.0;
NSArray *styles = #[[GMSStrokeStyle solidColor:kBaseColor],
[GMSStrokeStyle solidColor:[UIColor clearColor]]];
NSArray *lengths = #[#5, #5];
polyline.spans = GMSStyleSpans(polyline.path, styles, lengths, kGMSLengthRhumb);
GMSCoordinateBounds * bounds = [[GMSCoordinateBounds alloc]initWithCoordinate:startLocation coordinate:endLocation];
UIEdgeInsets insets = UIEdgeInsetsMake(20, 20, 20, 20);
GMSCameraPosition * camera = [mapView cameraForBounds:bounds insets:insets ];
[mapView animateToCameraPosition:camera];
}
Swift 5+
Very easy and Smooth way
//MARK: - Usage
let path = self.bezierPath(from: CLLocationCoordinate2D(latitude: kLatitude, longitude: kLongtitude), to: CLLocationCoordinate2D(latitude: self.restaurantLat, longitude: self.restaurantLong))
let polyline = GMSPolyline(path: path)
polyline.strokeWidth = 5.0
polyline.strokeColor = appClr
polyline.map = self.googleMapView // Google MapView
Simple Function
func drawArcPolyline(from startLocation: CLLocationCoordinate2D, to endLocation: CLLocationCoordinate2D) -> GMSMutablePath {
let distance = GMSGeometryDistance(startLocation, endLocation)
let midPoint = GMSGeometryInterpolate(startLocation, endLocation, 0.5)
let midToStartLocHeading = GMSGeometryHeading(midPoint, startLocation)
let controlPointAngle = 360.0 - (90.0 - midToStartLocHeading)
let controlPoint = GMSGeometryOffset(midPoint, distance / 2.0 , controlPointAngle)
let path = GMSMutablePath()
let stepper = 0.05
let range = stride(from: 0.0, through: 1.0, by: stepper)// t = [0,1]
func calculatePoint(when t: Double) -> CLLocationCoordinate2D {
let t1 = (1.0 - t)
let latitude = t1 * t1 * startLocation.latitude + 2 * t1 * t * controlPoint.latitude + t * t * endLocation.latitude
let longitude = t1 * t1 * startLocation.longitude + 2 * t1 * t * controlPoint.longitude + t * t * endLocation.longitude
let point = CLLocationCoordinate2D(latitude: latitude, longitude: longitude)
return point
}
range.map { calculatePoint(when: $0) }.forEach { path.add($0) }
return path
}

Are pointers to Objective-C arrays (via a bridging header) allowed?

I have been trying to get the GLCameraRipple sample from Apple running in a swift project. Unfortunately this relies heavily on using C style, thread-safe arrays only available in Objective-C.
I have been trying to use a bridging header so that the simulation can run in Objective-C code, and the drawing can run in swift code. That way the thread-safe thing would not be an issue.
I have taken the Objective-C code and translated it almost completely into swift with a few exceptions. I did cull some of the extra math since the texture is the same size as the screen for my needs. If you want to check my translation I have put them below.
Anyway I have made a class that will run in any xcode project with an opengl environment.
import Foundation
import GLKit
import OpenGLES
class WaterDrawer
{
static var sim = RippleModel()
static var shade = Shader("Shader2")
static func pt(pt: CGPoint)
{
sim.initiateRippleAtLocation(pt)
}
static func firstStart(width: Int, height: Int)
{
sim.initWithScreenWidth(width / 4, iheight: height / 4, accWidth: width, accHeight: height)
shade.begin()
buildMatrix(width, height: height)
bufferSetup()
}
static func draw()
{
glUseProgram(shade.progId)
let posLoc = GLuint(glGetAttribLocation(shade.progId, "pos"))
let texLoc = GLuint(glGetAttribLocation(shade.progId, "tc"))
glBindBuffer(GLenum(GL_ARRAY_BUFFER), texVBO);
glBufferData(GLenum(GL_ARRAY_BUFFER), GLsizeiptr(sim.getVertexSize()), sim.getTexCoords(), GLenum(GL_DYNAMIC_DRAW));
glVertexAttribPointer(texLoc, 2, GLenum(GL_FLOAT), GLboolean(GL_FALSE), 0, BUFFER_OFFSET(0))
glEnableVertexAttribArray(texLoc)
glBindBuffer(GLenum(GL_ARRAY_BUFFER), posVBO)
glVertexAttribPointer(posLoc, 2, GLenum(GL_FLOAT), GLboolean(GL_FALSE), 0, BUFFER_OFFSET(0))
glEnableVertexAttribArray(posLoc)
let uniOrtho = glGetUniformLocation(shade.progId, "matrix")
glUniformMatrix4fv(uniOrtho, 1, GLboolean(GL_FALSE), &orthographicMatrix)
glBindBuffer(GLenum(GL_ELEMENT_ARRAY_BUFFER), indVBO)
glDrawElements(GLenum(GL_TRIANGLE_STRIP), GLsizei(sim.getIndexCount()), GLenum(GL_UNSIGNED_SHORT), nil)
glBindBuffer(GLenum(GL_ARRAY_BUFFER), 0)
glBindBuffer(GLenum(GL_ELEMENT_ARRAY_BUFFER), 0)
glDisableVertexAttribArray(posLoc)
glDisableVertexAttribArray(texLoc)
}
static func update()
{
sim.runSimulation()
}
static var posVBO:GLuint = 0
static var texVBO:GLuint = 0
static var indVBO:GLuint = 0
static func bufferSetup()
{
Whirl.crashLog("Started passing in buffer data")
glGenBuffers(1, &indVBO);
glBindBuffer(GLenum(GL_ELEMENT_ARRAY_BUFFER), indVBO);
glBufferData(GLenum(GL_ELEMENT_ARRAY_BUFFER), GLsizeiptr(sim.getIndexSize()), sim.getIndices(), GLenum(GL_STATIC_DRAW));
glGenBuffers(1, &posVBO);
glBindBuffer(GLenum(GL_ARRAY_BUFFER), posVBO);
glBufferData(GLenum(GL_ARRAY_BUFFER), GLsizeiptr(sim.getVertexSize()), sim.getVertices(), GLenum(GL_STATIC_DRAW));
glGenBuffers(1, &texVBO);
glBindBuffer(GLenum(GL_ARRAY_BUFFER), texVBO);
glBufferData(GLenum(GL_ARRAY_BUFFER), GLsizeiptr(sim.getVertexSize()), sim.getTexCoords(), GLenum(GL_DYNAMIC_DRAW));
Whirl.crashLog("Finished passing in buffer Data")
}
static var orthographicMatrix:[GLfloat] = []
static func buildMatrix(width: Int, height: Int)
{
orthographicMatrix = glkitmatrixtoarray(GLKMatrix4MakeOrtho(0, GLfloat(width), 0, GLfloat(height), -100, 100))
//Storage.upScaleFactor
}
static func glkitmatrixtoarray(mat: GLKMatrix4) -> [GLfloat]
{
var buildme:[GLfloat] = []
buildme.append(mat.m.0)
buildme.append(mat.m.1)
buildme.append(mat.m.2)
buildme.append(mat.m.3)
buildme.append(mat.m.4)
buildme.append(mat.m.5)
buildme.append(mat.m.6)
buildme.append(mat.m.7)
buildme.append(mat.m.8)
buildme.append(mat.m.9)
buildme.append(mat.m.10)
buildme.append(mat.m.11)
buildme.append(mat.m.12)
buildme.append(mat.m.13)
buildme.append(mat.m.14)
buildme.append(mat.m.15)
return buildme
}
}
So theoretically this code can use either the swift implementation or the Objective-C implementation, I just need to switch the way the mesh is initiated.
Trouble is when I use the Objective-C one the screen is blank, I have checked, and the buffer data looks really weird in the frame capture.
Are you allowed to pass in data from an Objective-C code to a glBuffer?
Simulation.swift
import Foundation
import GLKit
import OpenGLES
class RippleModel
{
var screenWidth:UInt32 = 0
var screenHeight:UInt32 = 0
var poolWidth:UInt32 = 0
var poolHeight:UInt32 = 0
var screenWidthi:Int = 0
var screenHeighti:Int = 0
var poolWidthi:Int = 0
var poolHeighti:Int = 0
let touchRadius:Int = 5 //5 i think
var rippleVertices:[GLfloat] = []
var rippleTexCoords:[GLfloat] = []
var rippleIndices:[GLushort] = []//NOTE IF CHANGE THIS TO INTO SO MUCH DRAW CALL
var rippleSource:[GLfloat] = []
var rippleDest:[GLfloat] = []
var rippleCoeff:[GLfloat] = []
var VertexSize:GLsizeiptr = 0
var IndicieSize:GLsizeiptr = 0
var IndicieCount:Int = 0
func calculateSizes()
{
VertexSize = rippleVertices.count * sizeof(GLfloat)
IndicieSize = rippleIndices.count * sizeof(GLushort)
IndicieCount = rippleIndices.count
Whirl.crashLog("Data sizes Vertex size \(VertexSize)\tIndicie Size \(IndicieSize) \tIndicie Count \(IndicieCount)")
}
func figureOutCoefficent()
{
for y in 0...(2 * touchRadius)
{
for x in 0...(2 * touchRadius)
{
let dx = x - touchRadius
let dy = y - touchRadius
let distance = sqrt(GLfloat(dx * dx + dy * dy))
let me = y * (touchRadius*2 + 1) + x
if (distance <= GLfloat(touchRadius))
{
let factor = distance / GLfloat(touchRadius)
rippleCoeff[me] = -(cos(factor*GLfloat(M_PI))+1.0) * 256.0;
}
else
{
rippleCoeff[me] = 0.0
}
}
}
}
init()
{
}
func initWithScreenWidth( iwidth: Int, iheight: Int, accWidth: Int, accHeight: Int)
{
screenWidth = UInt32(accWidth);screenWidthi = Int(screenWidth)
screenHeight = UInt32(accHeight);screenHeighti = Int(screenHeight)
poolWidth = UInt32(iwidth);poolWidthi = Int(poolWidth)
poolHeight = UInt32(iheight);poolHeighti = Int(poolHeight)
//WE DONT NEED TEX COORD MUMBO JUMBO IT IS FULL SCREEN ALREADY
Whirl.crashLog("Started allocation")
rippleCoeff = [GLfloat](count: Int( (touchRadius * 2 + 1) * (touchRadius*2 + 1) ), repeatedValue: 0)
figureOutCoefficent()
let simCount:Int = Int(poolWidth + 2) * Int(poolHeight + 2)
rippleSource = [GLfloat](count: simCount, repeatedValue: 0)
rippleDest = [GLfloat](count: simCount, repeatedValue: 0)
let locb:Int = Int(poolWidth * poolHeight * 2)
rippleVertices = [GLfloat](count: locb, repeatedValue: 0)
rippleTexCoords = [GLfloat](count: locb, repeatedValue: 0)
rippleIndices = [GLushort](count: Int(poolHeight - 1) * Int((poolWidth * 2) + 2), repeatedValue: 0)
Whirl.crashLog("Finished allocation")
initMesh()
calculateSizes()
}
func initMesh()
{
Whirl.crashLog("Started initting pos coords")
for i in 0..<poolHeight
{let ii = GLfloat(i)
for j in 0..<poolWidth
{let jj = GLfloat(j)
let cordb:Int = Int(i*poolWidth+j)*2
rippleVertices[cordb + 0] = (jj / GLfloat(poolWidth - 1)) * GLfloat(screenWidth)
rippleVertices[cordb + 1] = (ii / GLfloat(poolHeight - 1)) * GLfloat(screenHeight)
rippleTexCoords[cordb + 0] = ii / GLfloat(poolHeight - 1)
rippleTexCoords[cordb + 1] = (jj/GLfloat(poolWidth - 1))
}
}
Whirl.crashLog("Finished initting pos coords")
Whirl.crashLog("Started initting index coords")
var index = 0
for i in 0 ..< poolHeighti-1
{
for j in 0 ..< poolWidthi
{
if (i%2 == 0)
{
// emit extra index to create degenerate triangle
if (j == 0)
{
rippleIndices[index] = GLushort(i*poolWidthi+j);
index += 1;
}
rippleIndices[index] = GLushort(i*poolWidthi+j);
index += 1;
rippleIndices[index] = GLushort((i+1)*poolWidthi+j);
index += 1;
// emit extra index to create degenerate triangle
if (j == (poolWidthi-1))
{
rippleIndices[index] = GLushort((i+1)*poolWidthi+j);
index += 1;
}
}
else
{
// emit extra index to create degenerate triangle
if (j == 0)
{
rippleIndices[index] = GLushort((i+1)*poolWidthi+j);
index += 1;
}
rippleIndices[index] = GLushort((i+1)*poolWidthi+j);
index += 1;
rippleIndices[index] = GLushort(i * poolWidthi + j);
index += 1;
// emit extra index to create degenerate triangle
if (j == (poolWidthi-1))
{
rippleIndices[index] = GLushort(i * poolWidthi + j);
index += 1;
}
}
}
}
Whirl.crashLog("Finished initting coords")
}
var firstUpdate = true
func runSimulation()
{
if (firstUpdate)
{firstUpdate = false; Whirl.crashLog("First update")}
let queue = dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0)
//dispatch_apply(Int(poolHeight), queue, {(y: size_t) -> Void in
for y in 0..<poolHeighti {
let pw = self.poolWidthi
for x in 1..<(pw - 1)
{
let ai:Int = (y ) * (pw + 2) + x + 1
let bi:Int = (y + 2) * (pw + 2) + x + 1
let ci:Int = (y + 1) * (pw + 2) + x
let di:Int = (y + 1) * (pw + 2) + x + 2
let me:Int = (y + 1) * (pw + 2) + x + 1
let a = self.rippleSource[ai]
let b = self.rippleSource[bi]
let c = self.rippleSource[ci]
let d = self.rippleSource[di]
var result = (a + b + c + d) / 2.0 - self.rippleDest[me]
result -= result / 32.0
self.rippleDest[me] = result
}
}
//)
let hm1 = GLfloat(poolHeight - 1)
let wm1 = GLfloat(poolWidth - 1)
//dispatch_apply(poolHeighti, queue, {(y: size_t) -> Void in
for y in 0..<poolHeighti{
let yy = GLfloat(y)
let pw = self.poolWidthi
for x in 1..<(pw - 1)
{let xx = GLfloat(x)
let ai:Int = (y ) * (pw + 2) + x + 1
let bi:Int = (y + 2) * (pw + 2) + x + 1
let ci:Int = (y + 1) * (pw + 2) + x
let di:Int = (y + 1) * (pw + 2) + x + 2
let a = self.rippleDest[ai]
let b = self.rippleDest[bi]
let c = self.rippleDest[ci]
let d = self.rippleDest[di]
var s_offset = ((b - a) / 2048)
var t_offset = ((c - d) / 2048)
s_offset = (s_offset < -0.5) ? -0.5 : s_offset;
t_offset = (t_offset < -0.5) ? -0.5 : t_offset;
s_offset = (s_offset > 0.5) ? 0.5 : s_offset;
t_offset = (t_offset > 0.5) ? 0.5 : t_offset;
let s_tc = yy / hm1
let t_tc = xx / wm1
let me = (y * pw + x) * 2
self.rippleTexCoords[me + 0] = s_tc + s_offset
self.rippleTexCoords[me + 1] = t_tc + t_offset
}
}
//)
let pTmp = rippleDest
rippleDest = rippleSource
rippleSource = pTmp
}
var firstRipple:Bool = true
func initiateRippleAtLocation(location: CGPoint)
{
if (firstRipple)
{firstRipple = false; Whirl.crashLog("First ripple placement")}
let xIndex = Int((GLfloat(location.x) / GLfloat(screenWidth)) * GLfloat(poolWidthi))
let yIndex = Int((1.0 - (GLfloat(location.y) / GLfloat(screenHeighti))) * GLfloat(poolHeight))
let lowy = yIndex - touchRadius
let highy = yIndex + touchRadius
let lowx = xIndex - touchRadius
let highx = xIndex + touchRadius
//Whirl.crashLog("Ripple at (\(xIndex) , \(yIndex))\tX:(\(lowx) - \(highx))\tY:(\(lowy) - \(highy))")
for y in lowy...highy
{
for x in lowx...highx
{
if (x > 0 && x < (poolWidthi - 1) && y > 0 && y < poolHeighti)
{
let ind = (poolWidthi + 2) * (y + 1) + x + 1
let coef = (y-(yIndex-touchRadius))*(touchRadius*2+1)+x-(xIndex-touchRadius)
let past = rippleSource[ind]
let coe = rippleCoeff[coef]
if (coe < past)
{
rippleSource[ind] = coe
}
}
}
}
}
func rippleLine(location1: CGPoint, location2: CGPoint)
{
if (firstRipple)
{firstRipple = false; Whirl.crashLog("First ripple placement")}
let xIndex1 = Int((GLfloat(location1.x) / GLfloat(screenWidth)) * GLfloat(poolWidthi))
let yIndex1 = Int((1.0 - (GLfloat(location1.y) / GLfloat(screenHeighti))) * GLfloat(poolHeight))
let xIndex2 = Int((GLfloat(location2.x) / GLfloat(screenWidth)) * GLfloat(poolWidthi))
let yIndex2 = Int((1.0 - (GLfloat(location2.y) / GLfloat(screenHeighti))) * GLfloat(poolHeight))
let lowy1 = yIndex1 - touchRadius
let highy1 = yIndex1 + touchRadius
let lowx1 = xIndex1 - touchRadius
let highx1 = xIndex1 + touchRadius
let lowy2 = yIndex2 - touchRadius
let highy2 = yIndex2 + touchRadius
let lowx2 = xIndex2 - touchRadius
let highx2 = xIndex2 + touchRadius
let lowx = min(lowx1, lowx2)
let highx = max(highx1, highx2)
let lowy = min(lowy1, lowy2)
let highy = max(highy1, highy2)
for y in lowy...highy
{
for x in lowx...highx
{
if (x > 0 && x < (poolWidthi - 1) && y > 0 && y < poolHeighti)
{
let ind = (poolWidthi + 2) * (y + 1) + x + 1
let tar = ldist(CGPoint(x: xIndex1, y: yIndex1), p2: CGPoint(x: xIndex2, y: yIndex2), me: CGPoint(x: x, y: y))
let dx = x - Int(tar.x)
let dy = y - Int(tar.y)
let distq = (dx * dx + dy * dy)
if (distq < touchRadius * touchRadius)
{
let factor = sqrt(GLfloat(distq)) / GLfloat(touchRadius)
rippleSource[ind] = -(cos(factor*GLfloat(M_PI))+1.0) * 256.0;
}
//rippleSource[ind] = 1000
}
}
}
}
func ldist(p1: CGPoint, p2: CGPoint, me: CGPoint) -> CGPoint
{
let diffX = p2.x - p1.x
let diffY = p2.y - p1.y
var target = CGPoint()
if ((diffX == 0) && (diffY == 0))
{
target = p1
}
let t = ((me.x - p1.x) * diffX + (me.y - p1.y) * diffY) / (diffX * diffX + diffY * diffY)
if (t < 0)
{
target = p1
}
else if (t > 1)
{
target = p2
}
else
{
target = CGPoint(x: (p1.x + t * diffX), y: (p1.y + t * diffY))
}
let int = CGPoint(x: round(target.x), y: round(target.y))
return int
}
func getVertices() -> [GLfloat]
{
//Return the mesh positions
return rippleVertices
}
func getTexCoords() -> [GLfloat]
{
//Return the array of texture coords
return rippleTexCoords
}
func getIndices() -> [GLushort]
{
//Return the array of indices
return rippleIndices
}
func getVertexSize() -> GLsizeiptr
{
//Return the size of the mesh position array
return VertexSize
}
func getIndexSize() -> GLsizeiptr
{
//Return the byte size of the incicie array
return IndicieSize
}
func getIndexCount() -> GLsizeiptr
{
//This goes in the draw call, count of indices
return IndicieCount
}
}
RippleModel.m (from apple)
Are you allowed to pass in data from an objective-c code to a glBuffer?
Why wouldn't you be allowed? Swift has a pointer API (UnsafePointer<T>, UnsafeMutablePointer<T>, etc.) exactly for this purpose. Obviously this is "unsafe" in the sense that the underlying memory the [Objective-]C pointer points to could change at anytime without the Swift pointer knowing. It also has no information about the size of the memory block that it points to.
Any C pointers or arrays can be bridged to Swift (probably as UnsafeMutablePointer<Void> which you will need to cast to your OpenGL type).
You can avoid any risk of referencing invalid memory by dereferencing the pointer (if it is non-nil) and copying the value stored at the pointer to a variable in your Swift application.
With OpenGL ES being a pure set of C functions, I don't think passing a pointer of swift datatypes will work easily.
The following code will give you a hint of how to pass the index buffer.
var Indices: [GLubyte] = [
0, 1, 2,
2, 3, 0
]
var indexBuffer: GLuint = GLuint()
glGenBuffers(1, &indexBuffer)
glBindBuffer(GLenum(GL_ELEMENT_ARRAY_BUFFER), indexBuffer)
glBufferData(GLenum(GL_ELEMENT_ARRAY_BUFFER), Indices.size(), Indices, GLenum(GL_STATIC_DRAW))
Reference: Here is a link with a working code. https://github.com/bradley/iOSSwiftOpenGL/blob/master/iOSSwiftOpenGL/OpenGLView.swift

Why is my screen not rendering anything?

I have the following code. When I run this I am getting a blank screen. This block of code is inside sceneDidLoad() so they will get executed but not displaying anything. Am I missing something ?
let worldNode = SKNode()
let height = 100
let width = 100
let regions:[Float: String] = [-0.04: "sand", -0.08: "water", 0.9: "grass"]
let noiseSource = GKPerlinNoiseSource()
let noise: GKNoise = GKNoise(noiseSource: noiseSource)
let noiseMap: GKNoiseMap = GKNoiseMap(noise: noise)
let tileMapNode = SKTileMapNode()
tileMapNode.enableAutomapping = true
tileMapNode.numberOfRows = height
tileMapNode.numberOfColumns = width
worldNode.addChild(tileMapNode)
for y in 0 ... height {
for x in 0 ... width {
let currentHeight = noiseMap.value(atPosition: vector2(Int32(x), Int32(y)));
for (key, value) in regions {
if (currentHeight <= key) {
//colourMap [y * mapChunkSize + x] = regions[i];
let tileSize = CGSize(width: 32.0, height: 32.0)
let tileTexture = SKTexture(imageNamed: value)
let tileDef = SKTileDefinition(texture: tileTexture, size: tileSize)
let tileGroup = SKTileGroup(tileDefinition: tileDef)
tileMapNode.setTileGroup(tileGroup, forColumn: x, row: y)
print("Tiling: \(value)")
break;
}
}
}
}
self.addChild(worldNode)

Resources