Post

Replies

Boosts

Views

Activity

Reply to Non-convex collision?
In general, decomposing a concave object into a set of convex objects is difficult. I.e. it's NP-Hard. There is lots of literature about this, including some approximation algorithms. Search the web. But I note that the original question referred to "terrain". Is this concave object terrain? That is an interesting special case which may be easier to solve. Note that I know next-to-nothing about ARKit / RealityKit, but I do know a fair bit about geometry algorithms in general.
Topic: Spatial Computing SubTopic: General Tags:
Mar ’24
Reply to How to set a price for in-app purchases so I get a specific amount after taxes and fees?
However, once I set a price on the App Store in USD, there is a large variation in the amount I will be paid from other countries and currencies as each country levies its own tax. Any workarounds or ways in which I can tell the App Store what I want to be paid after taxes so that prices are adjusted in each country accordingly?? In theory, that's what it is supposed to do. It is supposed to choose prices that give approximately the same proceeds for all countries; at https://developer.apple.com/help/app-store-connect/manage-app-pricing/set-a-price they say: "Automatically generated prices account for foreign exchange rates and certain taxes". In practice, they've got it badly wrong in some cases. I think that in part this is because they round customer prices to nice-looking numbers. For example, if I set my base GBP price to various values between £1 and £2, the automatic USD prices are always either $0.99 or $1.99; it never chooses anything in between. But that doesn't explain everything; I just discovered that a GBP base price of £98.90 is automatically converted to AU$149.99, which gives 15% lower proceeds; a much closer conversion would be AU$174.99. This actually worked better before they introduced the current system last year. So anyway... if you want the conversions to be more accurate than about +/- 30%, you will need to set prices manually, at least for the most important regions. It is possible to automate the process using the App Store Connect API; whether that is worth doing will depend on how many different prices you have and how good you are at wrangling JSON and deciphering Apple's docs. See also: https://developer.apple.com/forums/thread/732527 https://developer.apple.com/forums/thread/744277
Topic: App & System Services SubTopic: StoreKit Tags:
Mar ’24
Reply to Swift Cpp/c++ interop: swift functions with c++ enums arguments not available in c++
enum class MyCppEnum { D, E, F }; I think you meant enum MyCppEnum { D, E, F }; I can’t answer your question though. I think I have used swift enums in C++, but there was something nasty about it; maybe it mangled the names in some way? That’s right, it generated a non-class enum with the enum name prefixed to all the element names. I think it is safe to cast, rather than needing that switch.
Topic: Programming Languages SubTopic: Swift Tags:
Mar ’24
Reply to allowsBackgroundLocationUpdates clarifications
I think that if you have whenInUse auth, you can start getting updates in the foreground, then go to the background and continue to get them. Turning locations on while in the background may need the always auth. I take it you are using a bluetooth background mode in order to be running in the background with locations off, right? This is an unusual situation.
Topic: App & System Services SubTopic: Core OS Tags:
Mar ’24
Reply to Generates all possible subsets of a given set, excluding the empty set. (non sorted)
@JessyC , he wants combinations, not permutations. I note that the page you linked to does also have a combinations(ofCount:) function. But we want all combinations, not just combinaions of a particular size. Is there an all combinations function in there that I can't see? Anyway, here is a trivial recursive implementation: func getCombinations(s: Set<String>) -> Set<Set<String>> { var result: Set<Set<String>> = []; if (s.isEmpty) { result.insert([]); return result; } var ss = s; let first = ss.removeFirst(); let subsets = getCombinations(s: ss); for sub in subsets { result.insert(sub); result.insert(sub.union([first])); } return result; } Note that includes the empty set, so the caller would need to remove that. That takes 15 seconds to compute the 8 million combinations of 23 inputs: var s : Set = ["a", "b", "c", "d", "e", "f", "g", "h", "i", "j", "k", "l", "m", "n", "o", "p", "q", "r", "s", "t", "u", "v", "w" //, "x", "y", "z" ]; //print("Input:", s); print("Input size = ", s.count); let combinations = getCombinations(s: s); // print("Output:", combinations); print("Output size = ", combinations.count); Here's a version that uses a binary counter. The idea is that you count from 1 to 2^n-1, and each bit pattern indicates a subset of the input elements: func getCombination(s: Array<String>, i: Int) -> Set<String> { var result: Set<String> = []; for j in 0 ... (s.count - 1) { if ((i >> j) & 1 == 1) { result.insert(s[j]); } } return result; } func getCombinations(s: Array<String>) -> Set<Set<String>> { assert(s.count < 32); var result: Set<Set<String>> = []; for i in 1 ... ((1 << s.count) - 1) { result.insert(getCombination(s: s, i: i)); } return result; } func getCombinations(s: Set<String>) -> Set<Set<String>> { let a = Array(s); return getCombinations(s: a); } Annoyingly it is fractionally slower than the recursive version. We can make it much faster by using more Arrays and fewer Sets. In particular, appending to an array is much quicker than inserting into a set (and we know the elements we're adding are unique). So: func getCombination(s: Array<String>, i: Int) -> Array<String> { var result: Array<String> = []; for j in 0 ... (s.count - 1) { if ((i >> j) & 1 == 1) { result.append(s[j]); } } return result; } func getCombinations(s: Array<String>) -> Array<Array<String>> { assert(s.count < 32); var result: Array<Array<String>> = []; for i in 1 ... ((1 << s.count) - 1) { result.append(getCombination(s: s, i: i)); } return result; } func getCombinations(s: Set<String>) -> Array<Array<String>> { let a = Array(s); return getCombinations(s: a); } I don't know how InvaDerSim wants to use this, but I suggest not trying to have all the combinations in memory at the same time if there are a lot of them. Instead have a callback and pass the combinations one at a time: func getCombination(s: Array<String>, i: Int) -> Array<String> { var result: Array<String> = []; for j in 0 ... (s.count - 1) { if ((i >> j) & 1 == 1) { result.append(s[j]); } } return result; } func getCombinations(s: Array<String>, cbk: (Array<String>)->Void) { assert(s.count < 32); for i in 1 ... ((1 << s.count) - 1) { cbk(getCombination(s: s, i: i)); } } func getCombinations(s: Set<String>, cbk: (Array<String>)->Void) { let a = Array(s); getCombinations(s: a, cbk: cbk); } ... except it actually isn't any faster! (But it does work for 26 input elements, which the previous version doesn't.) Finally, here's a C++ version: #include <bit> #include <cassert> #include <iostream> #include <set> #include <string> #include <vector> static auto getCombination(const std::vector<std::string>& s, int i) { std::vector<std::string> result; result.reserve(std::popcount(i)); // <-- edited to add this for (int j = 0; j < s.size(); ++j) { if (((i >> j) & 1) == 1) { result.insert(result.end(), s[j]); } } return result; } static void getCombinations(const std::vector<std::string>& s, auto cbk) { assert(s.size() < 32); for (auto i = 1; i < (1 << s.size()); ++i) { cbk(getCombination(s, i)); } } static void getCombinations(const std::set<std::string>& s, auto cbk) { std::vector<std::string> a {s.begin(),s.end()}; getCombinations(a, cbk); } int main() { std::set<std::string> s = { "a", "b", "c", "d", "e", "f", "g", "h", "i", "j", "k", "l", "m", "n", "o", "p", "q", "r", "s", "t", "u", "v", "w", "x", "y", "z" }; std::cout << "Input size = " << s.size() << "\n"; auto n = 0; getCombinations(s, [&] (auto combination) { // std::cout << combination << "\n"; n += 1; }); std::cout << "Output size = " << n << "\n"; return 0; } Its runtime is about 60% 33% of the swift version. Beware when benchmarking that it has the potential to optimise away too much to give a useful answer. (Edit: runtime approximately halved by adding reserve(std::popcount(i)).) Second edit to add this: We can make it much faster by using boost::container::static_vector instead of std::vector: #include <boost/container/static_vector.hpp> ... static auto getCombination(const std::vector<std::string>& s, unsigned int i) { boost::container::static_vector<std::string, 32> result; // or boost::container::small_vector<std::string, 32> result; ... The point is that the static_vector is stack-allocated, not heap-allocated. That gives a runtime of less than 10% of the swift code. I hope this is useful. I've done it really to improve my Swift! Feedback regarding that would be appreciated, i.e. that's a challenge to get the swift code as fast as my C++ version. One interesting language point is that the expression (i >> j) & 1 == 1 requires extra parenthesis in C++ because the relative priority of & and == differ, but in C++ I can omit the ==1 entirely as it will implicitly convert to bool.
Topic: Programming Languages SubTopic: Swift Tags:
Mar ’24
Reply to Seeking Advice: Navigating App Review for Complex, Server-Dependent iOS App
I think you misunderstand app review. They do about 4 things, in my experience: ”Virus scan”-type analysis of the app to see if you have included anything naughty. Not a problem except when they have false positives. An automated analysis of your app metadata to see if you mention Android or anything else they don’t like. They run the app once to see if it crashes on launch. If you have in-app purchase they will try to make sure that they work. Just submit your app and see what happens. If they reject it, don’t try to “communicate” or “document”, just do exactly what they tell you to do and resubmit.
Mar ’24