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)