Application d'aide à la conception de parapente
Airdrien
Membre
Bonjour à tous,
suite à nos premiers échanges et présentations, je vous propose mon projet d'application.
L'objectif principal de l'application en question est d'aider à la conception de parapentes.
Jusqu'à maintenant je définissais des paramètres de conceptions dans une feuille excel pour ensuite construire le modèle 3D avec Rhino Mac (beta). Mise à plat des surfaces tirées avec Rhino et impression sur plan, possiblement directement sur rouleau de tissu.
L'appli devrait au moins se substituer à la feuille excel et permettre d'étudier de nombreuses conceptions différentes et effectuer une étude paramétrique du comportement de l'aile. L'analyse numérique (étude aérodynamique) n'est pas une priorité pour le moment mais serait souhaitable à terme.
Quoiqu'il en soit, un parapente n'est qu'un assemblage cousu de panneaux de tissu, quelques joncs, renforts, pattes d'ancrage, suspentes, etc. L'appli devra fournir le minimum de données nécessaires à la construction de ces éléments avec Rhino et au mieux rendre le modèle en 3D puis mettre à plat les panneaux.
J'ai déjà un peu travaillé sur une façon de dessiner la forme à plat et la voûte de l'aile, au sein de NSView, avec des NSPoint et NSBezierPath. Il est temps de construire un Modèle complet et robuste, accompagné de vues et contrôleurs, mais je ne parviens pas à mettre en oeuvre une méthode MVC.
Avez-vous des conseils pour l'élaboration de mon modèle?
Remarque : je travaille avec XCode 3.4 (de mémoire) sous Snow Leopard (à jour).
En prime : une copie d'écran de l'appli au stade embryonnaire...
suite à nos premiers échanges et présentations, je vous propose mon projet d'application.
L'objectif principal de l'application en question est d'aider à la conception de parapentes.
Jusqu'à maintenant je définissais des paramètres de conceptions dans une feuille excel pour ensuite construire le modèle 3D avec Rhino Mac (beta). Mise à plat des surfaces tirées avec Rhino et impression sur plan, possiblement directement sur rouleau de tissu.
L'appli devrait au moins se substituer à la feuille excel et permettre d'étudier de nombreuses conceptions différentes et effectuer une étude paramétrique du comportement de l'aile. L'analyse numérique (étude aérodynamique) n'est pas une priorité pour le moment mais serait souhaitable à terme.
Quoiqu'il en soit, un parapente n'est qu'un assemblage cousu de panneaux de tissu, quelques joncs, renforts, pattes d'ancrage, suspentes, etc. L'appli devra fournir le minimum de données nécessaires à la construction de ces éléments avec Rhino et au mieux rendre le modèle en 3D puis mettre à plat les panneaux.
J'ai déjà un peu travaillé sur une façon de dessiner la forme à plat et la voûte de l'aile, au sein de NSView, avec des NSPoint et NSBezierPath. Il est temps de construire un Modèle complet et robuste, accompagné de vues et contrôleurs, mais je ne parviens pas à mettre en oeuvre une méthode MVC.
Avez-vous des conseils pour l'élaboration de mon modèle?
Remarque : je travaille avec XCode 3.4 (de mémoire) sous Snow Leopard (à jour).
En prime : une copie d'écran de l'appli au stade embryonnaire...
Connectez-vous ou Inscrivez-vous pour répondre.
Réponses
Comment developper un projet de type MVC qui puisse correspondre a mon projet d'appli mac os x?
Peut etre un tutoriel sur la methode avec le code de base?
Je suis debutant et encore peu familier de l'objective C mais je me debrouille avec les vues. Je ne parviens pas a transposer les exemple de MVC et NSTableView a quelque chose de plus general quitte a la jouer plus en "manuel".
Une bonne piste serait la bienvenue.
Merci pour vos reponses
L'idée du MVC c'est que les données métier (le Modèle) sont séparées de leur représentation (la vue).
Pour l'instant, tu as travaillé sur la vue. Ainsi, quand on dessine une aile, on place des points avec des coordonnées vue.
Je pense que tu as compris que dans le modèle, on va parler de coordonnées physiques. Ainsi, on peut considérer qu'on y parle en mètres.
Voici comment je m'y prendrais.
Modèle
Point
Déjà , je crée un type synonyme de double, pour indiquer des longueurs physiques:
Je peux alors définir un point. On pourrait utiliser une structure:
mais, je crois que ce n'est pas judicieux, parce que typiquement, on voudra modifier les coordonnées du point en tapant dans un champ, et il vaut donc mieux utiliser une classe:
Sommet
Je définis un Sommet comme l'association d'un point d'ancrage et de deux points de contrôle:
Voile
Une voile est décrite par une liste de sommets:
Tu n'oublieras évidemment pas d'instancier vertices dans -init.
Vue
Pour les vues, le plus simple est qu'elles prennent directement la liste des sommets en entrée.
Pour la vue de face:
Pareil pour la vue de haut. Ce sont les mêmes sommets:
Pour le reste, tu l'as déjà fait en grande partie: il faut de projeter les sommets et de dessiner le tout avec un NSBezierPath. Evidemment, tu auras des problèmes d'échelle, à toi de jouer.
Contrôleur
Il est de fait très simple: il va instancier une voile, alors il devra conserver une référence dessus. Il possède aussi des outlets vers les deux vues:
J'ai utilisé un NSViewController, mais ça peut être un NSWindowController.
Il lui faudra créer une voile (par exemple, dans sa méthode initWithNibName...,)
Lorsque les vues sont prêtes, dans la méthode -awakeFromNib, il faudra alors passer la voile aux deux vues:
Voilà , ça devrait être un bon début.
Voici mon code :
MODELE :
Cette init est un test, les coordonnées devraient donner une belle forme, mais sans réalité métrique pour l'instant.
C'est ma custom view qui fonctionne en autonomie, avant le passage en MVC
OK là c'est beaucoup de code inutile et surtout la manipulation du BezierPath avec les points est peu élégante, voire inapropriée si je veux modifier mon modèle à la souris. Cela fonctionnait en autonomie avant MVC.
Il doit y avoir pas mal de boulettes dans ce code...
A minima je voudrais que mon appli s'ouvre et affiche le modèle "de base" que l'utilisateur pourra ensuite modifier.
Pour rappel, je suis en Document Based app, je n'ai pas touché à MyDocument.
Dans IB j'ai ajouté mon View Controller et mis sa classe à ParaViewController, lié l'IBOutlet VaultView à ma custom view et l'IBAction generateVaultShape du contrôleur à un bouton.
Quand je clique ce bouton j'ai :
2013-01-28 14:08:49.428 ParaApp[1301:a0f] -[NSButton setX:]: unrecognized selector sent to instance 0x10013ce80
2013-01-28 14:08:49.429 ParaApp[1301:a0f] -[NSButton setX:]: unrecognized selector sent to instance 0x10013ce80
Je présume que repartir de zéro serait judicieux, pour éclaircir ce code peu élégant, c'est pas un soucis, je préfère faire propre que continuer à bidouiller en vain...
Là , apparemment, tu essayes d'utiliser la méthode setX sur un NSButton qui ne la connaà®t pas...
c'est surtout que mon modèle reste vide.
Là je tente avec NSLog de valider la méthode generateVaultShape sans succès. Cette méthode doit générer une forme standard. Mon controleur ressemble à ca maintenant :
Dans le log j'ai tout = 0.00000...
J'ai vu ça. Du coup j'ai enlevé l'action du bouton et transformé la méthode en -(void)generateVaultShape, appelée directement dans awakeFromNib.
Je dois retourner bosser (jusqu'à 19h), dites moi si je fais fausse route. Merci pour votre aide (à un débutant qui cafouille!) /implore.gif' class='bbc_emoticon' alt=' ' />
Je ne fais pas de développement sur Mac OSX, et je t'avouerais que j'ai un peu la flemme de lire tout ton code. J'ai juste regardé l'erreur de la console et dit ce que j'en pensais.
- si on entretient une synchro vue/modèle, déplacer un point horizontalement dans la vue de haut le déplace horizontalement dans le modèle. Donc, le déplace également horizontalement dans la vue de face.
- en interne, on utilise des unités métriques, on pourrait donc, par exemple, fournir le fichier à une machine de découpe.
- on peut saisir les coordonnées d'un point directement en unités métriques.
En l'état, ton code ne me semble pas si mal. Il y a des choses qui peuvent être simplifiées, mais c'est un bon début.
J'ai pas écris ça. Intéresse-toi à la gestion mémoire pour voir quelle est la différence entre (assign|weak|strong).
ARC est-il activé dans ton projet ?
Utilise le débogeur (mets des points d'arrêt dans la marre de gauche) pour vérifier l'état des variables, tu vas vite comprendre ce qui ne marche pas.
Evite les chiffres dans ton code, du genre for(i=0; i<3; i++), on ne sait pas à quoi correspond le 3. Et tu ne sauras plus non plus dans un mois.
J'utilise XCode 3, pas d'ARC il me semble.
A la place de strong je dois utiliser retain?
Et pour weak, assign?
Exact. Ta machine est trop ancienne pour Xcode 4 ?
Oui.
Oui.
Par contre, du coup, je ne sais pas pourquoi tu ne vois rien.
J'ai un macbook core 2 duo 2.0 GHz, late 2006, je suis resté sous Snow Leopard. Lion tourne mais ça rame.
A propos du contrôleur :
Il faut écraser la méthode du contrôleur? Je l'ai pas fait.
j'ai tout repris à 0 pour faire propre, mais j'ai une erreur dans awakefromnib avec alloc et init :
2013-01-29 12:44:18.735 ParApp[4681:a0f] VaultShape:init
Program received signal: “EXC_BAD_ACCESSâ€.
Tu as choisi un modèle Document-Based, et c'est très bien.
Comme je ne le savais pas, je suis resté assez vague sur la classe du contrôleur, te parlant de NSViewController ou NSWindowController.
Instancier le Modèle est le rôle du Contrôleur. Comme tu utilises l'architecture NSDocument, c'est ta sous-classe de NSDocument qui va l'instancier et qui va le retenir en mémoire:
MyDocument.h:
MyDocument.m:
Il s'agit d'un signal envoyé par le système d'exploitation. Il indique que le programme a tenté d'accéder à une zone mémoire sans autorisation. La raison classique est que tu as conservé un pointeur sur un objet qui n'existe plus en mémoire.
A priori, ce serait vaultShape.vertices.
La propriété vertices est un NSMutableArray que je n'arrive pas à remplir correctement.
Quand je veux récupérer les objets ajoutés les uns après les autres, ils sont tous égaux au dernier ajout.
Voilà le code :
et voilà le log :
Running...
2013-02-02 23:25:48.582 ParApp[3848:a0f] generateVaultShape
2013-02-02 23:25:48.585 ParApp[3848:a0f] x:425.000000 y:375.000000 z:0.000000
2013-02-02 23:25:48.586 ParApp[3848:a0f] x:650.000000 y:325.000000 z:0.000000
2013-02-02 23:25:48.587 ParApp[3848:a0f] x:725.000000 y:210.000000 z:0.000000
2013-02-02 23:25:48.588 ParApp[3848:a0f] x:510.000000 y:375.000000 z:0.000000
2013-02-02 23:25:48.589 ParApp[3848:a0f] x:595.000000 y:355.000000 z:0.000000
2013-02-02 23:25:48.589 ParApp[3848:a0f] x:705.000000 y:295.000000 z:0.000000
2013-02-02 23:25:48.590 ParApp[3848:a0f] x:735.000000 y:250.000000 z:0.000000
2013-02-02 23:25:48.591 ParApp[3848:a0f] point0 x:735.000000 y:250.000000 z:0.000000
2013-02-02 23:25:48.592 ParApp[3848:a0f] point1 x:735.000000 y:250.000000 z:0.000000
2013-02-02 23:25:48.592 ParApp[3848:a0f] point2 x:735.000000 y:250.000000 z:0.000000
2013-02-02 23:25:48.593 ParApp[3848:a0f] point3 x:735.000000 y:250.000000 z:0.000000
2013-02-02 23:25:48.593 ParApp[3848:a0f] point4 x:735.000000 y:250.000000 z:0.000000
2013-02-02 23:25:48.594 ParApp[3848:a0f] point5 x:735.000000 y:250.000000 z:0.000000
2013-02-02 23:25:48.595 ParApp[3848:a0f] point6 x:735.000000 y:250.000000 z:0.000000
2013-02-02 23:25:48.595 ParApp[3848:a0f] 7
2013-02-02 23:25:48.596 ParApp[3848:a0f] point0 x:735.000000 y:250.000000 z:0.000000
2013-02-02 23:25:48.597 ParApp[3848:a0f] point1 x:735.000000 y:250.000000 z:0.000000
2013-02-02 23:25:48.598 ParApp[3848:a0f] point2 x:735.000000 y:250.000000 z:0.000000
2013-02-02 23:25:48.599 ParApp[3848:a0f] point3 x:735.000000 y:250.000000 z:0.000000
2013-02-02 23:25:48.599 ParApp[3848:a0f] point4 x:735.000000 y:250.000000 z:0.000000
2013-02-02 23:25:48.602 ParApp[3848:a0f] point5 x:735.000000 y:250.000000 z:0.000000
2013-02-02 23:25:48.603 ParApp[3848:a0f] point6 x:735.000000 y:250.000000 z:0.000000
Debugger stopped.
Program exited with status value:0.
Autrement dit, quand tu fais un [vertices addObject:vertice], tu ajoutes l'objet vertice dans le tableau vertices, et ce n'est pas une copie de cet objet qui sera rajouté au tableau mais bien une référence à l'objet lui-même (si tu as déjà fait du C ou C++ et connais le concept de pointeur, sache qu'en Objective-C, tous les objets sont des pointeurs, d'où l'étoile dans "PhysicalVertex *" par exemple).
Donc forcément, si tu modifies l'objet vertice même après l'avoir ajouté dans le tableau, puisque c'est unen référence qui est dans le tableau cette référence sera modifiée aussi ! Au final c'est comme si tu disais "je me fais une liste (tableau) avec toutes les voitures que je connais" et que tu mets sur cette liste "La voiture de Paul, la voiture de Jacques et la voiture de Sylvie". Si la voiture de Paul était bleue quand tu as fait cette liste, mais que Paul décide de repeindre sa voiture en rouge un jour, ça restera la voiture de Paul qui sera inscrite sur ta liste, même si elle a changé de couleur (même si ses propriétés ont changé, comme pour ton PhysicalVertex)
---
Donc ce qu'il faut faire dans ton cas c'est :
1) soit mettre une copie de ton PhysicalVertex dans ton tableau plutôt que le PhysicalVertex directement, comme ça même si tu modifies ton PhysicalVertex d'origine, la copie que tu as mise dans ton NSMutableArray ne sera cette fois-ci pas impacté par les changements de valeur de l'original
2) soit, plus logiquement pour ton cas, créer un nouveau PhysicalVertex à chaque fois, pour ne pas mettre à chaque fois le même dans ton tableau, mais à chaque fois une instance différente.
1) faire un constructeur de commodité pour tes classes, genre une méthode "+[PhysicalVertex vertexWithAnchor:]" pour tes vertices et "+[PhysicalPoint pointWithX: y: z:]" pour tes points, chacune de ces méthodes faisant un alloc, un init(*) puis affectant les propriétés adéquates de cette nouvelle instance, pour enfin retourner cet objet déjà rempli (avec un "autorelease" avant de le retourner si jamais tu n'as pas activé ARC).
Ca te permettrait ensuite de créer chaque PhysicalPoint en une seule ligne plutôt que d'avoir pour chaque point à écrire 4 ou 5 lignes, genre Tu pourrais presque même prévoir un constructeur de commodité directement pour pouvoir écrire [PhysicalVertex vertexWithAnchorAtX:595 y:355 z:0] histoire d'économiser encore du code à taper ensuite /wink.png' class='bbc_emoticon' alt=';)' />
2) Surcharger la méthode "-(NSString*)description" (ou "-(NSString*)debugDescription") de tes classes, pour que quand tu appelles NSLog(@%@", ...) sur un objet de type PhysicalPoint par exemple, ça t'affiche la description de ce point directement (ses valeurs x,y et z typiquement), et du coup le NSLog que tu fais dans ta boucle ressemblera juste à :
(*) d'ailleurs tu as oublié dans ton code de faire un init sur ton PhysicalPoint, ne jamais faire un alloc sans faire de init associé ça peut t'amener des problèmes surtout en Release où les variables ne sont sinon pas mises à zéro avant de commencer et pourraient avoir des valeurs farfelues[/i]
Merci beaucoup, je vais pouvoir avancer !
/implore.gif' class='bbc_emoticon' alt=' ' />
et ça aussi y'a pas de raison !
ou encore :
Note les minuscules pour y et z.
J'ai toujours un problème (ça va devenir une habitude !)
Pour créer une forme de voûte de base, j'ai une méthode dans MyDocument et un push bouton.
Cette action appelle une méthode de la classe VaultShape en première ligne, qui crée une forme donnée de départ :
Tout se passe bien au premier clic, mais au deuxième : Program received signal: “EXC_BAD_ACCESSâ€.
Je pense que l'erreur est dans la méthode de mon modèle, car mes NSLog ne s'affichent pas au deuxième clic.
Très curieusement, si je double clique rapidement, le log est :
2013-02-04 14:25:57.032 ParApp[12373:a0f] MODELE : point0 X=425.000000 Y=390.000000 Z=0.000000
2013-02-04 14:25:57.034 ParApp[12373:a0f] MODELE : point1 <00000000 00002c40 00000000 00002840 00000000 00a06040 00000000 00004040>
Program received signal: “EXC_BAD_ACCESSâ€.
Il semble donc que la méthode de mon modèle (VaulShape) s'exécute, peut-être avant une libération non souhaitée et que je ne trouve pas!
(Instruments est une application qui fait partie des outils de dev. Je ne sais plus si on peut le lancer directement depuis Xcode 3).
Lion tourne correctement sur mon MacBookPro de 2005. Je l'ai bourré de RAM raz la gueule : le double du max donné par Apple.
J'avais un zombie dans ma méthode dealloc de la classe PhysicalVertex.
Ca fonctionne en supprimant son contenu (sauf super dealloc).
Mais on dirait que mon code est une vraie passoire /crybaby.gif' class='bbc_emoticon' alt=' ' /> Plus d'1Mo en deux minutes... Faudrait que je me plonge plus sérieusement dans la gestion de la mémoire...
Migrer n'est pas une priorité pas plus que développer une application à la pointe. Je suis limité à 3 Go de RAM soit diant mais j'ai quand même mis 4 /cool.gif' class='bbc_emoticon' alt='8--)' />
Mon appli risque de ne pas tourner sous Lion ou Mountain Lion ?
Un seul mot .. ARC !
Mais ça serait une grave erreur que de croire qu'utiliser ARC évite d'avoir à se plonger dans les mécanismes de gestion de la mémoire (en particulier la différence entre les weak et strong references ou les retain cycles etc) car ça, ARC ou non, ça fera quand même gonfler l'utilisation de la RAM et créera des fuites mémoire.
Sans parler d'avoir conscience de la différence entre strong et copy ou autres concepts, toujours valables même avec ARC et toujours à maà®triser, et qui ont un impact important sur l'empreinte mémoire d'une appli.
ARC aide énormément en faisant beaucoup de boulot pour nous. Les ZWR aident aussi a éviter les BadAccess. Mais croire que grâce a tout ça on peut se passer de connaà®tre les principes de gestion mémoire de Cocoa c'est l'erreur à ne pas faire !
Je ne pense pas que ce soit le problème. En fait, je pense qu'il n'y a pas de problème.
Les quelques classes que tu as créé doivent allouer quelques centaines d'octets. À mon avis, ce qui prend de la mémoire sont les nib, les bibliothèques de Cocoa, etc. Tu n'y peux rien.
Disons que Xcode 4 offre beaucoup de confort. Il m'est arrivé de retourner sous Xcode 3 pour compiler pour Mac OS 10.5, et le choc fut rude!
Il y a une compatibilité ascendante, mais il faudra quand même tester. Il arrive qu'on emploie mal les API, et ça peut fonctionner sous 10.6, mais plus sous 10.7.
Ceroce tu me rassures !
Merci a vous tous pour vos bons conseils, des que j'ai une version un tant soit peu fonctionnelle, je vous la soumets pour test Lion ;-)
Il est temps pour moi d'etoffer mon modele avec :
- une forme a plat,
- des profils,
- le suspentage.
Je vais avoir a discretiser VaultShape et FlatShape pour accueillir mes profils, equipes de points d'ancrages pour les suspentes.
Une idee pour transformer une forme de bezier constituee de 3 ou 4 vertices en une forme plus fournies?
Je pense aplatir la forme et cheminer dans une boucle pour ajouter des points.
L'utilisateur devra pouvoir choisir un nombre de profils et une loi de repartition, non lineaire car c'est trop simpliste et pas coherent avec l'etat de l'art.
Je vous en reparle dans un moment...
Encore merci !
Si je me souviens bien elle était pas très stable cette version.