Tesseract iOS camera low accuracy - ios

When I use an image taken with the camera on the iPhone and send it to tesseract the accuracy is horrible it is all garbage text, but when I choose the same image from the photo library I get great accuracy.
How can I improve tesseracts accuracy from a picture take with the camera? Here is what I am doing to the image before sending
- (void)imagePickerController:(UIImagePickerController *)picker didFinishPickingMediaWithInfo:(NSDictionary *)info {
UIImage *image = info[UIImagePickerControllerOriginalImage];
CGFloat newWidth = 1200;
CGSize newSize = CGSizeMake(newWidth, newWidth);
image = [image resizedImage:newSize interpolationQuality:kCGInterpolationHigh];
Tesseract* tesseract = [[Tesseract alloc]initWithLanguage:#"eng"];
[tesseract setVariableValue:#"0123456789abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ##&*()-_:." forKey:#"tessedit_char_whitelist"];
[tesseract setVariableValue:#"`~!%^*[]{}<>?|" forKey:#"tessedit_char_blacklist"];
[tesseract setImage:image];
[tesseract recognize];
NSLog(#"%#", [tesseract recognizedText]);
[picker dismissViewControllerAnimated:YES completion:NULL];
}
If anyone has found some "magical" way to get tesseract to scan with great accuracy I will reward a bounty!

Main things to consider:
Tesseract needs to be trained for the font and language being recognized.
It looks like you are supplying appropriate parameters here - are they the same that you use when you supply a predefined image?
Tesseract doesn't orientate, or 'clean up' images
When you pass an image to the library, it should already be cleaned up and in portrait. Is the
image in photo reel taken from the camera too, or is it a sample image you've saved there somehow?
One check to make is the resize function:
CGFloat newWidth = 1200;
CGSize newSize = CGSizeMake(newWidth, newWidth);
The original image will be distorted by this, since you are resizing a non-square image into a square image. This will definitely squash the text and make life difficult for Tesseract. At the very least, you want to preserve the aspect ratio of the captured image.

My code work fine, but it´s more complex
- (IBAction)captureTapped:(id)sender
{
NSMutableArray *results = [NSMutableArray array];
NSString *fullWord = #"";
OCRImplementation *ocr = [[OCRImplementation alloc] init];
for(int j = 0; j < [self.images count]; j++){
UIImage *imageToTesseract = [self.images objectAtIndex:j];
//UIImage *imageToTesseract = self.imgfinal.image;
NSMutableArray *sortedKeys = [NSMutableArray array];
#try {
sortedKeys = [ocr processImageDetectText:imageToTesseract threadhold:198];
}
#catch (NSException *exception) {
sortedKeys = [NSMutableArray array];
}
NSString *finalWord = #"";
if([sortedKeys count] > 0){
for(int i=0; i<[sortedKeys count]; i++){
UIImage *image = [sortedKeys objectAtIndex:i];
finalWord = [self confidencesOCRTesseract:image];
if(finalWord.length > 1){
finalWord = [NSString stringWithFormat:#"%c",[finalWord characterAtIndex:0]];
}
fullWord = [fullWord stringByAppendingString:finalWord];
}
}
fullWord = [fullWord stringByReplacingOccurrencesOfString:#"\n" withString:#""];
[results addObject:fullWord];
NSLog(#"-- RESULT -- %#",fullWord);
}
NSString *resultWord = #"";
if([results count] > 0){
resultWord = [self calculateStatics:results];
}
//Your text Result
NSLog(#"%#",resultWord);
}
- (NSString*)calculateStatics:(NSMutableArray*)results{
NSMutableArray *first = [NSMutableArray array];
NSMutableArray *second = [NSMutableArray array];
NSMutableArray *third = [NSMutableArray array];
NSMutableArray *fourth = [NSMutableArray array];
NSMutableArray *fifth = [NSMutableArray array];
NSMutableArray *six = [NSMutableArray array];
NSMutableArray *seven = [NSMutableArray array];
for(int i = 0; i<[results count]; i++){
NSString *result = [results objectAtIndex:i];
if(result && ![result isEqualToString:#""]){
if(result.length >= 1 && [result characterAtIndex:0]){
[first addObject:[NSString stringWithFormat:#"%c", [result characterAtIndex:0]]];
}else{
[first addObject:#" "];
}
if(result.length >= 2 &&[result characterAtIndex:1]){
[second addObject:[NSString stringWithFormat:#"%c", [result characterAtIndex:1]]];
}else{
[second addObject:#" "];
}
if(result.length >= 3 &&[result characterAtIndex:2]){
[third addObject:[NSString stringWithFormat:#"%c", [result characterAtIndex:2]]];
}else{
[third addObject:#" "];
}
if(result.length >= 4 &&[result characterAtIndex:3]){
[fourth addObject:[NSString stringWithFormat:#"%c", [result characterAtIndex:3]]];
}else{
[fourth addObject:#" "];
}
if(result.length >= 5 &&[result characterAtIndex:4]){
[fifth addObject:[NSString stringWithFormat:#"%c", [result characterAtIndex:4]]];
}else{
[fifth addObject:#" "];
}
if(result.length >= 6 &&[result characterAtIndex:5]){
[six addObject:[NSString stringWithFormat:#"%c", [result characterAtIndex:5]]];
}else{
[six addObject:#" "];
}
if(result.length >= 7 &&[result characterAtIndex:6]){
[seven addObject:[NSString stringWithFormat:#"%c", [result characterAtIndex:6]]];
}else{
[seven addObject:#" "];
}
}else{
[first addObject:#" "];
[second addObject:#" "];
[third addObject:#" "];
[fourth addObject:#" "];
[fifth addObject:#" "];
[six addObject:#" "];
[seven addObject:#" "];
}
}
NSString *word = #"";
NSCountedSet *frequencies = [NSCountedSet setWithArray:first];
if([frequencies count] == 1){
word = [word stringByAppendingString:[[frequencies allObjects] objectAtIndex:0]];
}else{
NSUInteger count = 0;
NSString *repeatedWord = #"";
for(int i=0; i<[frequencies count]; i++){
NSString *possibleWord = [[frequencies allObjects] objectAtIndex:i];
NSUInteger wordCount = [frequencies countForObject:possibleWord];
if(count < wordCount){
count = wordCount;
repeatedWord = possibleWord;
}
}
word = [word stringByAppendingString:repeatedWord];
}
NSCountedSet *frequencies2 = [NSCountedSet setWithArray:second];
if([frequencies2 count] == 1){
word = [word stringByAppendingString:[[frequencies2 allObjects] objectAtIndex:0]];
}else{
NSUInteger count = 0;
NSString *repeatedWord = #"";
for(int i=0; i<[frequencies2 count]; i++){
NSString *possibleWord = [[frequencies2 allObjects] objectAtIndex:i];
NSUInteger wordCount = [frequencies2 countForObject:possibleWord];
if(count < wordCount){
count = wordCount;
repeatedWord = possibleWord;
}
}
word = [word stringByAppendingString:repeatedWord];
}
NSCountedSet *frequencies3 = [NSCountedSet setWithArray:third];
if([frequencies3 count] == 1){
word = [word stringByAppendingString:[[frequencies3 allObjects] objectAtIndex:0]];
}else{
NSUInteger count = 0;
NSString *repeatedWord = #"";
for(int i=0; i<[frequencies3 count]; i++){
NSString *possibleWord = [[frequencies3 allObjects] objectAtIndex:i];
NSUInteger wordCount = [frequencies3 countForObject:possibleWord];
if(count < wordCount){
count = wordCount;
repeatedWord = possibleWord;
}
}
word = [word stringByAppendingString:repeatedWord];
}
NSCountedSet *frequencies4 = [NSCountedSet setWithArray:fourth];
if([frequencies4 count] == 1){
word = [word stringByAppendingString:[[frequencies4 allObjects] objectAtIndex:0]];
}else{
NSUInteger count = 0;
NSString *repeatedWord = #"";
for(int i=0; i<[frequencies4 count]; i++){
NSString *possibleWord = [[frequencies4 allObjects] objectAtIndex:i];
NSUInteger wordCount = [frequencies4 countForObject:possibleWord];
if(count < wordCount){
count = wordCount;
repeatedWord = possibleWord;
}
}
word = [word stringByAppendingString:repeatedWord];
}
NSCountedSet *frequencies5 = [NSCountedSet setWithArray:fifth];
if([frequencies5 count] == 1){
word = [word stringByAppendingString:[[frequencies5 allObjects] objectAtIndex:0]];
}else{
NSUInteger count = 0;
NSString *repeatedWord = #"";
for(int i=0; i<[frequencies5 count]; i++){
NSString *possibleWord = [[frequencies5 allObjects] objectAtIndex:i];
NSUInteger wordCount = [frequencies5 countForObject:possibleWord];
if(count < wordCount){
count = wordCount;
repeatedWord = possibleWord;
}
}
word = [word stringByAppendingString:repeatedWord];
}
NSCountedSet *frequencies6 = [NSCountedSet setWithArray:six];
if([frequencies6 count] == 1){
word = [word stringByAppendingString:[[frequencies6 allObjects] objectAtIndex:0]];
}else{
NSUInteger count = 0;
NSString *repeatedWord = #"";
for(int i=0; i<[frequencies6 count]; i++){
NSString *possibleWord = [[frequencies6 allObjects] objectAtIndex:i];
NSUInteger wordCount = [frequencies6 countForObject:possibleWord];
if(count < wordCount){
count = wordCount;
repeatedWord = possibleWord;
}
}
word = [word stringByAppendingString:repeatedWord];
}
NSCountedSet *frequencies7 = [NSCountedSet setWithArray:seven];
if([frequencies7 count] == 1){
word = [word stringByAppendingString:[[frequencies7 allObjects] objectAtIndex:0]];
}else{
NSUInteger count = 0;
NSString *repeatedWord = #"";
for(int i=0; i<[frequencies7 count]; i++){
NSString *possibleWord = [[frequencies7 allObjects] objectAtIndex:i];
NSUInteger wordCount = [frequencies7 countForObject:possibleWord];
if(count < wordCount){
count = wordCount;
repeatedWord = possibleWord;
}
}
word = [word stringByAppendingString:repeatedWord];
}
return word;
}
OCRImplementation class
OCRImplementation.h
#ifndef __TesseractSample__OCRImplementation__
#define __TesseractSample__OCRImplementation__
#endif /* defined(__TesseractSample__OCRImplementation__) */
#interface OCRImplementation : NSObject{
}
- (UIImage*)processImage:(id)sender;
- (NSString*)confidencesOCRTesseract:(UIImage*)picture;
#end
OCRImplementation.mm
#include "OCRImplementation.h"
#import <OpenCV/opencv2/imgproc/imgproc.hpp>
#import <OpenCV/opencv2/highgui/highgui.hpp>
#import "UIImage+OpenCV.h"
#import "Tesseract.h"
#import "baseapi.h"
#import "environ.h"
#import "pix.h"
#include <sstream>
#include <iostream>
#include <vector>
#include "OpenCV/opencv2/core/core.hpp"
#include "OpenCV/opencv2/features2d/features2d.hpp"
#include "OpenCV/opencv2/calib3d/calib3d.hpp"
#implementation OCRImplementation
- (NSMutableArray*)processImageDetectText:(id)sender threadhold:(int)threadhold{
UIImage *img1 = sender;
cv::Mat src = [img1 CVMat];
cv::Mat src_gray;
cv::Mat threshold_output;
cv::vector<cv::vector<cv::Point> > contours;
cv::vector<cv::Vec4i> hierarchy;
int thresh = 100;
cv::RNG rng(12345);
/// Convert image to gray and blur it
cvtColor( src, src_gray, CV_BGR2GRAY );
blur( src_gray, src_gray, cv::Size(3,3) );
/// Detect edges using Threshold
cv::threshold( src_gray, threshold_output, thresh, 255, cv::THRESH_BINARY );
/// Find contours
cv::findContours( threshold_output, contours, hierarchy, CV_RETR_TREE, CV_CHAIN_APPROX_SIMPLE, cv::Point(0, 0) );
/// Approximate contours to polygons + get bounding rects and circles
cv::vector<cv::vector<cv::Point> > contours_poly( contours.size() );
cv::vector<cv::Rect> boundRect( contours.size() );
cv::vector<cv::Point2f>center( contours.size() );
cv::vector<float>radius( contours.size() );
for( int i = 0; i < contours.size(); i++ )
{
approxPolyDP( cv::Mat(contours[i]), contours_poly[i], 3, true );
boundRect[i] = boundingRect( cv::Mat(contours_poly[i]) );
minEnclosingCircle( (cv::Mat)contours_poly[i], center[i], radius[i] );
}
/// Draw polygonal contour + bonding rects + circles
cv::Mat drawing = cv::Mat::zeros( threshold_output.size(), CV_8UC3 );
NSMutableDictionary *dictionaryImages = [NSMutableDictionary dictionary];
NSMutableArray *areaArray = [NSMutableArray array];
float lastArea = 0.0;
for( int i = 0; i< contours.size(); i++ )
{
cv::Scalar color = cv::Scalar( rng.uniform(0, 255), rng.uniform(0,255), rng.uniform(0,255) );
if(boundRect[i].height > 50){
double area = cv::contourArea(contours[i]);
if((boundRect[i].width < boundRect[i].height) && area > (lastArea / 2)){
lastArea = area;
[areaArray addObject:[NSString stringWithFormat:#"%f",area]];
rectangle( drawing, boundRect[i].tl(), boundRect[i].br(), color, 2, 8, 0 );
cv::Rect extendedRect = cv::Rect(boundRect[i].x - 5, boundRect[i].y - 5, boundRect[i].width + 10, boundRect[i].height + 10);
cv::Mat source = src;
cv::Mat target(extendedRect.size(), source.type());
if(0 <= extendedRect.x && 0 <= extendedRect.width && extendedRect.x + extendedRect.width <= source.cols && 0 <= extendedRect.y && 0 <= extendedRect.height && extendedRect.y + extendedRect.height <= source.rows){
source(extendedRect).copyTo(target);
//converting the original image into grayscale
cv::cvtColor(target, target, CV_BGR2GRAY);
cv::multiply(target, cv::Scalar(2,2,2), target);
cv::add(target, cv::Scalar(2,2,2), target);
/// Detect edges using Threshold
cv::threshold( target, threshold_output, threadhold, 255, cv::THRESH_BINARY );
cv::dilate(threshold_output, threshold_output, NULL);
UIImage *imgFinal = [OCRImplementation imageWithCVMat:threshold_output];
[dictionaryImages setObject:imgFinal forKey:[NSString stringWithFormat:#"%f", area]];
}else{
NSLog(#"Error al leer la imagen. NO ROI");
}
}
}
}
NSMutableDictionary *finalImages = [NSMutableDictionary dictionary];
NSMutableArray *sortedKeys = [NSMutableArray arrayWithArray:[areaArray sortedArrayUsingFunction:intSort context:NULL]];
for( int k = 0; k< contours.size(); k++ )
{
if(boundRect[k].height > 50){
for(int i = 0; i < [sortedKeys count]; i++){
double area = cv::contourArea(contours[k]);
if(area == [[sortedKeys objectAtIndex:i] floatValue]){
[finalImages setObject:[dictionaryImages objectForKey:[sortedKeys objectAtIndex:i]] forKey:[NSString stringWithFormat:#"%d",boundRect[k].x]];
}
}
}
}
NSMutableArray *array = [NSMutableArray array];
NSArray *keys = [finalImages allKeys];
NSArray *sortedKeys2 = [keys sortedArrayUsingFunction:intSortDesc context:NULL];
for(int i=0; i<[sortedKeys2 count]; i++){
[array addObject:[finalImages objectForKey:[sortedKeys2 objectAtIndex:i]]];
}
return array;
}
+ (UIImage *)imageWithCVMat:(const cv::Mat&)cvMat
{
NSData *data = [NSData dataWithBytes:cvMat.data length:cvMat.elemSize() * cvMat.total()];
CGColorSpaceRef colorSpace;
if (cvMat.elemSize() == 1) {
colorSpace = CGColorSpaceCreateDeviceGray();
} else {
colorSpace = CGColorSpaceCreateDeviceRGB();
}
CGDataProviderRef provider = CGDataProviderCreateWithCFData((CFDataRef)data);
CGImageRef imageRef = CGImageCreate(cvMat.cols, // Width
cvMat.rows, // Height
8, // Bits per component
8 * cvMat.elemSize(), // Bits per pixel
cvMat.step[0], // Bytes per row
colorSpace, // Colorspace
kCGImageAlphaNone | kCGBitmapByteOrderDefault, // Bitmap info flags
provider, // CGDataProviderRef
NULL, // Decode
false, // Should interpolate
kCGRenderingIntentDefault); // Intent
UIImage *image = [UIImage imageWithCGImage:imageRef];
CGImageRelease(imageRef);
CGDataProviderRelease(provider);
CGColorSpaceRelease(colorSpace);
return image;
}
- (NSString*)confidencesOCRTesseract:(UIImage*)picture{
tesseract::TessBaseAPI* tess;
uint32_t* _pixels;
NSString* _dataPath = #"tessdata";
NSString* _language = #"eng";
// Useful paths
NSFileManager *fileManager = [NSFileManager defaultManager];
NSArray *documentPaths = NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES);
NSString *documentPath = ([documentPaths count] > 0) ? [documentPaths objectAtIndex:0] : nil;
NSString *dataPath = [documentPath stringByAppendingPathComponent:_dataPath];
// Copy data in Doc Directory
if (![fileManager fileExistsAtPath:dataPath]) {
NSString *bundlePath = [[NSBundle mainBundle] bundlePath];
NSString *tessdataPath = [bundlePath stringByAppendingPathComponent:_dataPath];
if (tessdataPath) {
[fileManager copyItemAtPath:tessdataPath toPath:dataPath error:nil];
}
}
setenv("TESSDATA_PREFIX", [[documentPath stringByAppendingString:#"/"] UTF8String], 1);
tess = new tesseract::TessBaseAPI();
tess->Init([_dataPath UTF8String], [_language UTF8String]);
tess->SetVariable("save_blob_choices", "T");
tess->SetVariable("tessedit_char_whitelist", "ABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789");
//SET IMAGE
CGSize size = [picture size];
int width = size.width;
int height = size.height;
_pixels = (uint32_t *) malloc(width * height * sizeof(uint32_t));
// Clear the pixels so any transparency is preserved
memset(_pixels, 0, width * height * sizeof(uint32_t));
CGColorSpaceRef colorSpace = CGColorSpaceCreateDeviceRGB();
// Create a context with RGBA _pixels
CGContextRef context = CGBitmapContextCreate(_pixels, width, height, 8, width * sizeof(uint32_t), colorSpace,
kCGBitmapByteOrder32Little | kCGImageAlphaPremultipliedLast);
// Paint the bitmap to our context which will fill in the _pixels array
CGContextDrawImage(context, CGRectMake(0, 0, width, height), [picture CGImage]);
// We're done with the context and color space
CGContextRelease(context);
CGColorSpaceRelease(colorSpace);
tess->SetImage((const unsigned char *) _pixels, width, height, sizeof(uint32_t), width * sizeof(uint32_t));
//END SET IMAGE
tess->Recognize(NULL);
tesseract::ResultIterator* ri = tess->GetIterator();
tesseract::ChoiceIterator* ci;
// For every identified symbol (there should be only one...)
NSString *finalWord = #"";
if(ri != 0) {
do {
const char* symbol = ri->GetUTF8Text(tesseract::RIL_SYMBOL);
if(symbol != 0) {
float conf = ri->Confidence(tesseract::RIL_SYMBOL);
if(conf > 80.0f){
finalWord = [finalWord stringByAppendingString:[NSString stringWithUTF8String:symbol]];
}else{
const tesseract::ResultIterator itr = *ri;
ci = new tesseract::ChoiceIterator(itr);
// For every chosen candidate...
do {
const char* choice = ci->GetUTF8Text();
NSString *choiceStr = [NSString stringWithUTF8String:choice];
if(choice && ![choiceStr isEqualToString:#""]){
finalWord = [finalWord stringByAppendingString:choiceStr];
break;
}else{
finalWord = [finalWord stringByAppendingString:[NSString stringWithUTF8String:symbol]];
}
} while(ci->Next());
delete ci;
}
}
delete[] symbol;
} while((ri->Next(tesseract::RIL_SYMBOL)));
}
return finalWord;
}
NSInteger intSort(id num1, id num2, void *context) {
NSString *n1 = (NSString *) num1;
NSString *n2 = (NSString *) num2;
n1 = [[n1 componentsSeparatedByString:#"."] objectAtIndex:0];
n2 = [[n2 componentsSeparatedByString:#"."] objectAtIndex:0];
if ([n1 floatValue] > [n2 floatValue]) {
return NSOrderedAscending;
}
else if ([n1 floatValue] < [n2 floatValue]) {
return NSOrderedDescending;
}
return NSOrderedSame;
}
NSInteger intSortDesc(id num1, id num2, void *context) {
NSString *n1 = (NSString *) num1;
NSString *n2 = (NSString *) num2;
n1 = [[n1 componentsSeparatedByString:#"."] objectAtIndex:0];
n2 = [[n2 componentsSeparatedByString:#"."] objectAtIndex:0];
if ([n1 floatValue] < [n2 floatValue]) {
return NSOrderedAscending;
}
else if ([n1 floatValue] > [n2 floatValue]) {
return NSOrderedDescending;
}
return NSOrderedSame;
}
#end

Related

Wrong polyline drawing on map with Google Maps SDK

I'm trying to draw route on my map using Google Maps SDK.
This is the URL that i'm calling and I parse the JSON response to array of coordinates:
id jsonResponse = [NSJSONSerialization JSONObjectWithData:responseObject options:NSJSONReadingMutableContainers error:nil];
int points_count = 0;
points_count = [[[[[[jsonResponse objectForKey:#"routes"] objectAtIndex:0] objectForKey:#"legs"] objectAtIndex:0] objectForKey:#"steps"] count];
NSArray *steps = nil;
if (points_count && [[[[jsonResponse objectForKey:#"routes"] objectAtIndex:0] objectForKey:#"legs"] count])
{
steps = [[[[[jsonResponse objectForKey:#"routes"] objectAtIndex:0] objectForKey:#"legs"] objectAtIndex:0] objectForKey:#"steps"];
}
NSMutableArray *coordinates = [[NSMutableArray alloc] initWithCapacity:points_count];
for (int i = 0; i < points_count; i++)
{
NSDictionary *start;
NSDictionary *finish;
double st_lat = [[[[steps objectAtIndex:i] objectForKey:#"start_location"] valueForKey:#"lat"] doubleValue];
double st_lon = [[[[steps objectAtIndex:i] objectForKey:#"start_location"] valueForKey:#"lng"] doubleValue];
if (st_lat > 0.0f && st_lon > 0.0f)
{
start = #{ #"latitude" : [NSNumber numberWithDouble:st_lat], #"longitude" : [NSNumber numberWithDouble:st_lon] };
}
double end_lat = [[[[steps objectAtIndex:i] objectForKey:#"end_location"] valueForKey:#"lat"] doubleValue];
double end_lon = [[[[steps objectAtIndex:i] objectForKey:#"end_location"] valueForKey:#"lng"] doubleValue];
if (end_lat > 0.0f && end_lon > 0.0f)
{
finish = #{ #"latitude" : [NSNumber numberWithDouble:end_lat], #"longitude" : [NSNumber numberWithDouble:end_lon] };
}
[coordinates addObject:#{ #"start" : start, #"finish" : finish }];
}
And than drawing on the map view with this method:
GMSMutablePath *path = [GMSMutablePath path];
for (NSDictionary *d in directions)
{
NSDictionary *start = d[#"start"];
NSDictionary *finish = d[#"finish"];
CLLocationCoordinate2D c_start = CLLocationCoordinate2DMake([start[#"latitude"] doubleValue], [start[#"longitude"] doubleValue]);
CLLocationCoordinate2D c_finish = CLLocationCoordinate2DMake([finish[#"latitude"] doubleValue], [finish[#"longitude"] doubleValue]);
[path addCoordinate:c_start];
[path addCoordinate:c_finish];
}
GMSPolyline *line = [GMSPolyline polylineWithPath:path];
line.strokeColor = [UIColor redColor];
line.strokeWidth = 2.0f;
line.map = self.mapView;
Why it is drawing like that and not going into the street it self?
What am I doing wrong here?
Try this it draws exact path like in driving mode - StreetMode, Here's my code :
iOS GSMPolyLine
So the problem was that I used the start_location and end_location instead of the polyline -> points. Fixed my code into this:
Request URL for example: https://maps.googleapis.com/maps/api/directions/json?origin=40.716072,-74.008836&destination=40.697545,-73.983892&sensor=false&waypoints=optimize:true&mode=driving
id jsonResponse = [NSJSONSerialization JSONObjectWithData:responseObject options:NSJSONReadingMutableContainers error:nil];
int points_count = 0;
points_count = [[[[[[jsonResponse objectForKey:#"routes"] objectAtIndex:0] objectForKey:#"legs"] objectAtIndex:0] objectForKey:#"steps"] count];
NSArray *steps = nil;
if (points_count && [[[[jsonResponse objectForKey:#"routes"] objectAtIndex:0] objectForKey:#"legs"] count])
{
steps = [[[[[jsonResponse objectForKey:#"routes"] objectAtIndex:0] objectForKey:#"legs"] objectAtIndex:0] objectForKey:#"steps"];
}
NSMutableArray *coordinates = [[NSMutableArray alloc] initWithCapacity:points_count];
for (int i = 0; i < points_count; i++)
{
NSString *toDecode = [[[steps objectAtIndex:i] objectForKey:#"polyline"] valueForKey:#"points"];
NSArray *locations = [AppUtils decodePolylineWithString:toDecode];
for (int i = 0 ; i < locations.count ; i++)
{
if (i != locations.count - 1) {
CLLocation *start = [locations objectAtIndex:i];
CLLocation *finish = [locations objectAtIndex:i + 1];
[coordinates addObject:#{ #"start" : start, #"finish" : finish }];
}
}
}
GMSMutablePath *path = [GMSMutablePath path];
for (NSDictionary *d in directions)
{
CLLocation *start = d[#"start"];
CLLocation *finish = d[#"finish"];
[path addCoordinate:start.coordinate];
[path addCoordinate:finish.coordinate];
}
GMSPolyline *line = [GMSPolyline polylineWithPath:path];
line.strokeColor = [UIColor redColor];
line.strokeWidth = 2.0f;
line.map = self.mapView;
+ (NSArray*)decodePolylineWithString:(NSString *)encodedString
{
NSMutableArray *coordinates = [NSMutableArray array];
const char *bytes = [encodedString UTF8String];
NSUInteger length = [encodedString lengthOfBytesUsingEncoding:NSUTF8StringEncoding];
NSUInteger idx = 0;
NSUInteger count = length / 4;
CLLocationCoordinate2D *coords = calloc(count, sizeof(CLLocationCoordinate2D));
NSUInteger coordIdx = 0;
float latitude = 0;
float longitude = 0;
while (idx < length) {
char byte = 0;
int res = 0;
char shift = 0;
do {
byte = bytes[idx++] - 63;
res |= (byte & 0x1F) << shift;
shift += 5;
} while (byte >= 0x20);
float deltaLat = ((res & 1) ? ~(res >> 1) : (res >> 1));
latitude += deltaLat;
shift = 0;
res = 0;
do {
byte = bytes[idx++] - 0x3F;
res |= (byte & 0x1F) << shift;
shift += 5;
} while (byte >= 0x20);
float deltaLon = ((res & 1) ? ~(res >> 1) : (res >> 1));
longitude += deltaLon;
float finalLat = latitude * 1E-5;
float finalLon = longitude * 1E-5;
CLLocationCoordinate2D coord = CLLocationCoordinate2DMake(finalLat, finalLon);
coords[coordIdx++] = coord;
CLLocation *location = [[CLLocation alloc] initWithLatitude:finalLat longitude:finalLon];
[coordinates addObject:location];
if (coordIdx == count) {
NSUInteger newCount = count + 10;
coords = realloc(coords, newCount * sizeof(CLLocationCoordinate2D));
count = newCount;
}
}
free(coords);
return coordinates;
}
I know it's a little bit dirty, but that's work and it works great.
Enjoy.

Route drawing on Google Maps for iOS not following the street lines

I'm developing an iOS app which is using Google Directions API to draw routes on maps which are provided by Google Maps SDK. It works well on small distance although when I zoom the map camera very close I see that the route polylines are often getting out of the streets. When the distance is longer it's a real disaster and it's not following the streets curves if I zoom in. I'm getting the points from the overview-polyline which I receive from the Directions API but it seems like the polyline is not that poly as I want. On Android it works perfectly. Could it be that Google sends different directions to iOS than Android? Has some of you had the same problem as me?
EDIT:
-(int) requestDirecionsAndshowOnMap:(GMSMapView *)aMapView{
NSArray* mode=[[NSArray alloc]initWithObjects:#"transit",#"bicycling",#"walking",#"driving", nil];
NSString *depart=[[NSString alloc] initWithFormat:#""];
NSString *origin=[[NSString alloc] initWithFormat:#""];
NSString *destination=[[NSString alloc] initWithFormat:#""];
if (self.setLanguage)
self.setLanguage=[NSString stringWithFormat:#"language=%#",self.setLanguage];
else self.setLanguage=#"language=en";
if (searchModeOption==0) {
if (self.departDate==nil) {
self.departDate=[NSDate date];
}
depart=[NSString stringWithFormat:#"&departure_time=%i",(int)[self.departDate timeIntervalSince1970]];
}
if (self.origin) {
origin=[NSString stringWithFormat:#"origin=%#",self.origin];
}else if (self.originCoordinate.latitude && self.originCoordinate.longitude){
origin=[NSString stringWithFormat:#"origin=%f,%f",self.originCoordinate.latitude,self.originCoordinate.longitude];
}else{
NSLog(#"No origin setted");
return -1;
}
if (self.destination) {
destination=[NSString stringWithFormat:#"destination=%#",self.destination];
}else if (self.destinationCoordinate.latitude && self.destinationCoordinate.longitude){
destination=[NSString stringWithFormat:#"destination=%f,%f",self.destinationCoordinate.latitude,self.destinationCoordinate.longitude];
}else{
NSLog(#"No destination setted");
return -1;
}
NSString* URLforRequest=[[NSString stringWithFormat:#"http://maps.googleapis.com/maps/api/directions/json?%#&%#&sensor=false&%#&alternative=false&mode=%#%#",origin,destination,self.setLanguage,[mode objectAtIndex:searchModeOption],depart] stringByAddingPercentEscapesUsingEncoding: NSASCIIStringEncoding];
// NSLog(#"%#",URLforRequest);
NSURLRequest *requests = [NSURLRequest requestWithURL:[NSURL URLWithString:URLforRequest]];
[NSURLConnection sendAsynchronousRequest:requests queue:[NSOperationQueue mainQueue] completionHandler:^(NSURLResponse *response, NSData *data, NSError *error){
if (error==nil && data) {
// NSLog(#"%#",[[NSString alloc] initWithData:data encoding:NSUTF8StringEncoding]);
directions = [NSJSONSerialization JSONObjectWithData:data options:NSJSONReadingMutableLeaves error:&error];
if (error) {
NSLog(#"%#",error);
}
NSString* status=[directions objectForKey:#"status"];
NSLog(#"Status: %#", status);
if ([status isEqualToString:#"OK"]) {
[self decodeResult];
if (aMapView)
[self showOnMap:aMapView];
}
}else NSLog(#"%#",error);
[[NSNotificationCenter defaultCenter] postNotificationName:#"Request Done" object:nil];
}];
return 0;
}
-(void) decodeResult{
self.destination=[[[[[directions objectForKey:#"routes"] objectAtIndex:0] objectForKey:#"legs"] objectAtIndex:0] objectForKey:#"end_address"];
self.distance=[[[[[[[directions objectForKey:#"routes"] objectAtIndex:0] objectForKey:#"legs"] objectAtIndex:0] objectForKey:#"distance"] objectForKey:#"text"] doubleValue];
self.duration=[[[[[[directions objectForKey:#"routes"] objectAtIndex:0] objectForKey:#"legs"] objectAtIndex:0] objectForKey:#"duration"] objectForKey:#"text"];
//Get Array of Instructions
self.instrunctions=[[NSMutableArray alloc] init];
for (int n=0; n<[[[[[[directions objectForKey:#"routes"] objectAtIndex:0] objectForKey:#"legs"] objectAtIndex:0] objectForKey:#"steps"]count]; n++) {
[self.instrunctions addObject:[[[[[[[directions objectForKey:#"routes"] objectAtIndex:0] objectForKey:#"legs"] objectAtIndex:0] objectForKey:#"steps"] objectAtIndex:n] objectForKey:#"html_instructions"]];
}
//Get Overview Polyline
NSString *polystring=[[[[directions objectForKey:#"routes"] objectAtIndex:0] objectForKey:#"overview_polyline"] objectForKey:#"points"];
NSMutableArray* decodedpolystring=[self decodePolyLine:polystring];
int numberOfCC=[decodedpolystring count];
GMSMutablePath *path = [GMSMutablePath path];
for (int index = 0; index < numberOfCC; index++) {
CLLocation *location = [decodedpolystring objectAtIndex:index];
CLLocationCoordinate2D coordinate = location.coordinate;
[path addLatitude:coordinate.latitude longitude:coordinate.longitude];
}
self.overviewPolilyne= [GMSPolyline polylineWithPath:path];
//Get Coordinates of origin and destination to be displayed on a map
float lat=[[[[[[[directions objectForKey:#"routes"] objectAtIndex:0] objectForKey:#"legs"]objectAtIndex:0] objectForKey:#"end_location"] objectForKey:#"lat"] floatValue];
float lng=[[[[[[[directions objectForKey:#"routes"] objectAtIndex:0] objectForKey:#"legs"]objectAtIndex:0] objectForKey:#"end_location"] objectForKey:#"lng"] floatValue];
CLLocationCoordinate2D tmp;
tmp.latitude=lat;
tmp.longitude=lng;
self.destinationCoordinate=tmp;
lat=[[[[[[[directions objectForKey:#"routes"] objectAtIndex:0] objectForKey:#"legs"]objectAtIndex:0] objectForKey:#"start_location"] objectForKey:#"lat"] floatValue];
lng=[[[[[[[directions objectForKey:#"routes"] objectAtIndex:0] objectForKey:#"legs"]objectAtIndex:0] objectForKey:#"start_location"] objectForKey:#"lng"] floatValue];
tmp.latitude=lat;
tmp.longitude=lng;
self.originCoordinate=tmp;
}
-(NSMutableArray *)decodePolyLine:(NSString *)encodedStr {
NSMutableString *encoded = [[NSMutableString alloc] initWithCapacity:[encodedStr length]];
[encoded appendString:encodedStr];
[encoded replaceOccurrencesOfString:#"\\\\" withString:#"\\"
options:NSLiteralSearch
range:NSMakeRange(0, [encoded length])];
NSInteger len = [encoded length];
NSInteger index = 0;
NSMutableArray *array = [[NSMutableArray alloc] init];
NSInteger lat=0;
NSInteger lng=0;
while (index < len) {
NSInteger b;
NSInteger shift = 0;
NSInteger result = 0;
do {
b = [encoded characterAtIndex:index++] - 63;
result |= (b & 0x1f) << shift;
shift += 5;
} while (b >= 0x20);
NSInteger dlat = ((result & 1) ? ~(result >> 1) : (result >> 1));
lat += dlat;
shift = 0;
result = 0;
do {
b = [encoded characterAtIndex:index++] - 63;
result |= (b & 0x1f) << shift;
shift += 5;
} while (b >= 0x20);
NSInteger dlng = ((result & 1) ? ~(result >> 1) : (result >> 1));
lng += dlng;
NSNumber *latitude = [[NSNumber alloc] initWithFloat:lat * 1e-5];
NSNumber *longitude = [[NSNumber alloc] initWithFloat:lng * 1e-5];
CLLocation *location = [[CLLocation alloc] initWithLatitude:[latitude floatValue] longitude:[longitude floatValue]];
[array addObject:location];
}
return array;
}
-(void)showOnMap:(GMSMapView *)aMapView{
GMSPolyline *polyline =self.overviewPolilyne;
polyline.strokeColor = [UIColor blueColor];
polyline.strokeWidth = 2.f;
//polyline.geodesic = YES;
polyline.map = aMapView; }
UPDATE:
I had to process every step's polyline, not just the overview-polyline. Now it works perfectly.
Here's the code I'm using now:
// Get polyline
GMSMutablePath *path = [GMSMutablePath path];
NSMutableArray *polyLinesArray = [[NSMutableArray alloc] init];
int zero=0;
NSArray *steps = [[[[[directions objectForKey:#"routes"] objectAtIndex:zero] objectForKey:#"legs"] objectAtIndex:0] objectForKey:#"steps"];
for (int i=0; i<[[[[[[directions objectForKey:#"routes"] objectAtIndex:zero] objectForKey:#"legs"] objectAtIndex:0] objectForKey:#"steps"]count]; i++) {
NSString* encodedPoints =[[[steps objectAtIndex:i]objectForKey:#"polyline"]valueForKey:#"points"];
polyLinesArray = [self decodePolyLine:encodedPoints];
NSUInteger numberOfCC=[polyLinesArray count];
for (NSUInteger index = 0; index < numberOfCC; index++) {
CLLocation *location = [polyLinesArray objectAtIndex:index];
CLLocationCoordinate2D coordinate = location.coordinate;
[path addLatitude:coordinate.latitude longitude:coordinate.longitude];
if (index==0) {
[self.coordinates addObject:location];
}
}
}
self.overviewPolilyne = [GMSPolyline polylineWithPath:path];
What I basically did before was that I was getting and working only with the information I'm receiving in the routes while if you check the JSON file you're receiving from Google Directions API, you'll see that you receive much more information in the <legs> and the <steps>. This is the information we need to produce the proper results and the right polyline.
Good luck! :)

How to add string and array

NSString *butterfly = [NSString stringWithFormat:#"brush_%d.png", i]
I want that string in separate like this
brush_
%d.png
Because i have lot of animation function are there in my project(0 to 39).
if(counter == 0) {
NSMutableArray *dashBoy = [NSMutableArray array];
for (i = 1; i<= 13; i++) {
butterfly = [NSString stringWithFormat:#"brush_%d.png", i];
if ((image = [UIImage imageNamed:butterfly]))
[dashBoy addObject:image];
}
[stgImageView setAnimationImages:dashBoy];
[stgImageView setAnimationDuration:2.0f];
[stgImageView startAnimating];
}
.
.
if(counter == 39) {
NSMutableArray *dashBoy1 = [NSMutableArray array];
for (i = 1; i <= 30; i++) {
butterfly = [NSString stringWithFormat:#"catch_%d.png", i];
if ((image = [UIImage imageNamed:butterfly]))
[dashBoy1 addObject:image];
}
[stgImageView setAnimationImages:dashBoy1];
[stgImageView setAnimationDuration:7.20f];
[stgImageView startAnimating];
}
I tried this but it's not correct
NSArray *c = [NSArray arrayWithObjects:#"brush", #"catch", #"clap",#"dog", nil];
//NSString *str = #"brush_";
NSString *str = [c componentsJoinedByString:#""];
for (int i=0; i<=3;i++)
str = [str stringByAppendingFormat:#"_%i.png ",i];
NSLog(#"%#",str); //Output is brushcatchclapdog_0.png _1.png _2.png _3.png
I want
brush_0.png, catch_1.png, clap_2.png in array
Here i want to combine in one function using for loop above category.It is possible to get one function to combine the above 39 animation function.
[self animateWithCategory:#"brush_" WithCount:13 duration:0.2f]
-(void)animateWithCategory:(NSString *)strCategory WithCount:(CGFloat)count duration:(NSInteger)duration{
NSMutableArray *dashBoy = [NSMutableArray array];
for (int i = 1; i<= count; i++) {
NSString* butterfly = [NSString stringWithFormat:#"%#%d.png",strCategory ,i];
UIImage *image=[UIImage imageNamed:butterfly];
[dashBoy addObject:image];
}
[stgImageView setAnimationImages:dashBoy];
[stgImageView setAnimationDuration:duration];
[stgImageView setAnimationRepeatCount:1];
[stgImageView startAnimating];
}
As per your desired output:
I want
brush_0.png, catch_1.png, clap_2.png in array
you can try like this:
NSArray *c = [NSArray arrayWithObjects:#"brush", #"catch", #"clap",#"dog", nil];
NSMutableArray *o = [[NSMutableArray alloc] initWithCapacity:[c count]];
//NSString *str = #"brush_";
//NSString *str = [c componentsJoinedByString:#""];
for (int i=0; i<=3;i++)
{
NSString *str = [[c objectAtIndex:i] stringByAppendingFormat:#"_%i.png ",i];
NSLog(#"%#",str); //Output is brushcatchclapdog_0.png _1.png _2.png _3.png
[o addObject:str];
}//brush_0.png, catch_1.png, clap_2.png in array
NSLog(#"Output array : %#", o);
Logged output of the code:
2014-02-07 00:31:29.020 DesignMantic[807:70b] brush_0.png
2014-02-07 00:31:29.023 DesignMantic[807:70b] catch_1.png
2014-02-07 00:31:29.024 DesignMantic[807:70b] clap_2.png
2014-02-07 00:31:29.025 DesignMantic[807:70b] dog_3.png
2014-02-07 00:31:29.026 DesignMantic[807:70b] Output array : (
"brush_0.png ",
"catch_1.png ",
"clap_2.png ",
"dog_3.png "
)

With what coordinates do i use to manually draw a custom path with an MKMapView?

There are CLLocation2D points, MKMapPoints, MKCoordinates, and convertCoordinate:toPointInView: which all give you points in one form or another. I am drawing a custom route in:
- (void)drawMapRect:(MKMapRect)mapRect zoomScale:(MKZoomScale)zoomScale inContext:(CGContextRef)context {
Whats the proper point to use for drawing?
routeView = [[UIImageView alloc] initWithFrame:CGRectMake(0, 0, mapView.frame.size.width, mapView.frame.size.height)];
routeView.userInteractionEnabled = NO;
[mapView addSubview:routeView];
And
-(void) updateRouteView {
CGContextRef context = CGBitmapContextCreate(nil,
routeView.frame.size.width,
routeView.frame.size.height,
8,
4 * routeView.frame.size.width,
CGColorSpaceCreateDeviceRGB(),
kCGImageAlphaPremultipliedLast);
CGContextSetStrokeColorWithColor(context, lineColor.CGColor);
CGContextSetRGBFillColor(context, 0.0, 0.0, 1.0, 1.0);
CGContextSetLineWidth(context, 4.0);
for(int i = 0; i < self.routes.count; i++) {
CLLocation* location = [self.routes objectAtIndex:i];
CGPoint point = [mapView convertCoordinate:location.coordinate toPointToView:routeView];
if(i == 0) {
CGContextMoveToPoint(context, point.x, routeView.frame.size.height - point.y);
} else {
CGContextAddLineToPoint(context, point.x, routeView.frame.size.height - point.y);
}
}
CGContextStrokePath(context);
CGImageRef image = CGBitmapContextCreateImage(context);
UIImage* img = [UIImage imageWithCGImage:image];
routeView.image = img;
CGContextRelease(context);
}
You can use google api like-
Define approirate variable in .h-
NSArray *arrRoutePoints;
MKPolygon *objpolygon;
MKPolyline *objpolyline;
Call function like where you want -
self.arrRoutePoints=[self getRoutePointFrom:newSource to:newDestination];
[self drawRoute];
Function Code :
- (NSArray*)getRoutePointFrom:(MKPointAnnotation *)origin to:(MKPointAnnotation *)destination
{
NSString *saddress=[NSString stringWithFormat:#"%f,%f",origin.coordinate.latitude,origin.coordinate.longitude];
NSString *daddress=[NSString stringWithFormat:#"%f,%f",destination.coordinate.latitude,destination.coordinate.longitude];
NSString *apiUrlString=[NSString stringWithFormat:#"http://maps.google.com/maps?output=dragdir&saddr=%#&daddr=%#", saddress, daddress];
NSURL *apiUrl=[NSURL URLWithString:apiUrlString];
NSError *error;
NSString *apiResponse=[NSString stringWithContentsOfURL:apiUrl encoding:NSUTF8StringEncoding error:&error];
NSRange range;
range=[apiResponse rangeOfString:#"points:\\\"([^\\\"]*)\\\"" options:NSRegularExpressionSearch];
NSString *encodedPoint=[apiResponse substringWithRange:range];
NSLog(#"Encode lentgh %d",[encodedPoint length]);
encodedPoint=[encodedPoint stringByReplacingOccurrencesOfString:#"points:\"" withString:#""];
encodedPoint=[encodedPoint stringByReplacingOccurrencesOfString:#"\"" withString:#""];
return [self decodePolyLine:[encodedPoint mutableCopy]];
}
- (NSMutableArray *)decodePolyLine:(NSMutableString *)encodedString
{
[encodedString replaceOccurrencesOfString:#"\\\\" withString:#"\\"
options:NSLiteralSearch
range:NSMakeRange(0, [encodedString length])];
NSInteger len = [encodedString length];
NSInteger index = 0;
NSMutableArray *array = [[NSMutableArray alloc] init];
NSInteger lat=0;
NSInteger lng=0;
while (index < len) {
NSInteger b;
NSInteger shift = 0;
NSInteger result = 0;
do {
b = [encodedString characterAtIndex:index++] - 63;
result |= (b & 0x1f) << shift;
shift += 5;
} while (b >= 0x20);
NSInteger dlat = ((result & 1) ? ~(result >> 1) : (result >> 1));
lat += dlat;
shift = 0;
result = 0;
do {
if(index<len)
{
b = [encodedString characterAtIndex:index++] - 63;
result |= (b & 0x1f) << shift;
shift += 5;
}
else
{
break;
}
} while (b >= 0x20);
NSInteger dlng = ((result & 1) ? ~(result >> 1) : (result >> 1));
lng += dlng;
NSNumber *latitude = [[NSNumber alloc] initWithFloat:lat * 1e-5];
NSNumber *longitude = [[NSNumber alloc] initWithFloat:lng * 1e-5];
printf("\n[%f,", [latitude doubleValue]);
printf("%f]", [longitude doubleValue]);
CLLocation *loc = [[CLLocation alloc] initWithLatitude:[latitude floatValue] longitude:[longitude floatValue]];
[array addObject:loc];
}
return array;
}
- (void)drawRoute
{
int numPoints=[arrRoutePoints count];
if(numPoints >1)
{
CLLocationCoordinate2D *coord=malloc(numPoints *sizeof(CLLocationCoordinate2D));
for(int i=0;i<numPoints;i++)
{
CLLocation *current=[arrRoutePoints objectAtIndex:i];
NSLog(#"%#",[arrRoutePoints objectAtIndex:i]);
NSLog(#"Current \n[%g",current.coordinate.latitude);
NSLog(#"%g]",current.coordinate.longitude);
coord[i]=current.coordinate;
NSLog(#"\n[%g",coord[i].latitude);
NSLog(#"%g]",coord[i].longitude);
}
self.objpolyline=[MKPolyline polylineWithCoordinates:coord count:numPoints];
free(coord);
[mapView addOverlay:objpolyline];
[mapView setNeedsDisplay];
}
}

words from letters

I am working in iOS, and I am facing one problem. I have 6 letters, and I want to find all strings that can be generated by these 6 letters. The sequence and length of the string doesn't matter here, also the meaning of the string doesn't matter because we can check the string with a dictionary to find if it is a valid word or not.
So is there any algorithm to find this?
For example:
Input 6 letters are : N T L P A E
Expected output will be:
plan
net
planet
lan
tea
lap
..
..
Here the words in the output are only the valid words, but the output should contain all possible words, even invalid words.
This should probably solve this:
+ (void) logPermutations:(NSArray*)objects
{
if (objects == nil || [objects count] == 0) {
return;
}
NSMutableArray* copy = [objects mutableCopy];
[self logPermutations:copy logedSoFar:#""];
}
+ (void) logPermutations:(NSMutableArray*)objects
logedSoFar:(NSString*)log
{
if (objects == nil || [objects count] == 0) {
return;
}
NSUInteger count = [objects count];
for (NSUInteger i = 0; i < count; ++i) {
id removed = [objects objectAtIndex:i];
[objects removeObjectAtIndex:i];
NSString* newlog = [NSString stringWithFormat:#"%#%#",log,[removed description]];
NSLog(#"%#",newlog);
[self logPermutations:objects logedSoFar:newlog];
[objects insertObject:removed atIndex:i];
}
}
-(NSMutableArray*)genValidWords:(NSString*)tiles
{
/*===============EMPTY PREVIOUS ARRAY=================*/
FINAL_VALID_WORDS=[[NSMutableArray alloc] init];
posWords=[[NSMutableArray alloc] init];
genWords=[[NSArray alloc] init];
/*============EMPTY PREVIOUS ARRAY FINISH=============*/
/*===============POSSIABLE NO OF WORDS FROM GIVEN LETTERS=================*/
int length=[tiles length];
int total=0;
for(long i=2;i<[tiles length]+1;i++)
total=total+([self factorialX:length]/[self factorialX:length-i]);
NSLog(#"POSSIABLE NO OF WORDS FROM LETTERS \"%#\" IS %d",tiles,total);
/*===============POSSIABLE NO OF WORDS FROM GIVEN LETTERS FINISH=================*/
/*===============GET ARRAY OF ALL POSSIABLE WORDS FROM GIVEN LETTERS=============*/
for(int i=2;i<[tiles length]+1;i++)
{
genWords=getPermutations(tiles, i);
[posWords addObjectsFromArray:genWords];
}
NSLog(#"%#",posWords);
return posWords;
}
static NSMutableArray *results;
void doPermute(NSMutableArray *input, NSMutableArray *output, NSMutableArray *used, int size, int level)
{
if (size == level)
{
NSString *word = [output componentsJoinedByString:#""];
//if(check(word))
[results addObject:word];
return;
}
level++;
for (int i = 0; i < input.count; i++)
{
if ([used[i] boolValue])
{
continue;
}
used[i] = [NSNumber numberWithBool:YES];
[output addObject:input[i]];
doPermute(input, output, used, size, level);
used[i] = [NSNumber numberWithBool:NO];
[output removeLastObject];
}
}
NSArray *getPermutations(NSString *input, int size)
{
results = [[NSMutableArray alloc] init];
NSMutableArray *chars = [[NSMutableArray alloc] init];
for (int i = 0; i < [input length]; i++)
{
NSString *ichar = [NSString stringWithFormat:#"%c", [input characterAtIndex:i]];
[chars addObject:ichar];
}
NSMutableArray *output = [[NSMutableArray alloc] init];
NSMutableArray *used = [[NSMutableArray alloc] init];
for (int i = 0; i < chars.count; i++)
{
[used addObject:[NSNumber numberWithBool:NO]];
}
doPermute(chars, output, used, size, 0);
return results;
}
-(double) factorialX: (int) num {
double tempResult = 1;
for (int i=2; i<=num; i++) {
tempResult *= i;
}
return tempResult;
}
/*=======================Call Like this====================
NSmutableArray=getPermutations("Pass your string", pass your lenght);
NsmutableArray=getPermutations("Janak", 2);
NSMutableArray=[self genValidWords:#"Hello"];
will return all possiable combination of two letters
=======================xxxxxxxxxx====================*/
I got the solution,
I want something like following.
-(NSArray*)totalWords:(NSArray*)letters
{
NSMutableArray *output=[[NSMutableArray alloc]init];
for (int i=0; i<letters.count; i++)
{
for (int j=0; j<letters.count; j++)
{
if (i==j) continue;
for (int k=0; k<letters.count; k++)
{
NSString *str=[NSString stringWithFormat:#"%#%#%#",letters[i],letters[j],letters[k]];
if(i!=j && j!=k && i!=k &&[self checkmeaning:str])
[output addObject:str];
for (int l=0; l<letters.count; l++)
{
NSString *str=[NSString stringWithFormat:#"%#%#%#%#",letters[i],letters[j],letters[k],letters[l]];
if(i!=j && j!=k && i!=k && l!=i && l!=j && l!=k &&[self checkmeaning:str])
[output addObject:str];
for (int m=0; m<letters.count; m++)
{
NSString *str=[NSString stringWithFormat:#"%#%#%#%#%#",letters[i],letters[j],letters[k],letters[l],letters[m]];
if(i!=j && j!=k && i!=k && l!=i && l!=j && l!=k && m!=i && m!=j && m!=k && m!=l &&[self checkmeaning:str])
[output addObject:str];
for (int n=0; n<letters.count; n++)
{
NSString *str=[NSString stringWithFormat:#"%#%#%#%#%#%#",letters[i],letters[j],letters[k],letters[l],letters[m],letters[n]];
if(i!=j && j!=k && i!=k && l!=i && l!=j && l!=k && m!=i && m!=j && m!=k && n!=i && n!=j && n!=k &&n!=m &&n!=l && m!=l&&[self checkmeaning:str])
[output addObject:str];
}
}
}
}
}
}
NSLog(#"count :%i",[output count]);
NSLog(#"output array :\n%#",output);
return output;
}

Resources