This is MiscCoordConverter.m in view mode; [Download] [Up]
/*========================= MiscCoordConverter.m ============================*/ /* MiscCoordConverter is an abstract super class that supports the writing of converters between coordinate systems. All values are double precision floating point numbers representing locations in a three dimensional coordinate system. DMA Release 0.8, Copyright @1993 by Genesis Project, Ltd. All Rights Reserved. For further information on terms and conditions see the MiscKit license. HISTORY 10-Mar-93 Dale Amon at GPL Created. */ #import <misckit/miscgiskit.h> @implementation MiscCoordConverter /*===========================================================================*/ /* Internal Class Subcontractor support methods */ /*===========================================================================*/ /* register a converter to the list of conversion subcontractors */ static id subcontractors = nil; /* Master list of converters */ + registerSubcontractor: aConverter { if (!subcontractors) subcontractors = [[List allocFromZone:[self zone]] init]; [subcontractors addObjectIfAbsent: aConverter]; return self; } /*---------------------------------------------------------------------------*/ /* unregister a converter from the list of conversion subcontractors */ + unregisterSubcontractor: aConverter { [subcontractors removeObject:aConverter]; return self; } /*---------------------------------------------------------------------------*/ /* get the name of the next one in the list */ + getSubcontractor:(unsigned int) n {return [subcontractors objectAt:n];} /*===========================================================================*/ /* General Class methods */ /*===========================================================================*/ /* Initialize the class */ + initialize {[MiscCoordConverter setVersion:MISC_COORD_CONVERTER_VERSION_ID]; return self;} /*===========================================================================*/ /* Initialization methods */ /*===========================================================================*/ /* We cache everything that we will need repeatedly, ie the class id's of all the MiscCoord classes we know how to service. Every instance of a converter is registered so it can be subcontracted to. */ - init { [MiscCoordConverter registerSubcontractor: self]; return self; } /*---------------------------------------------------------------------------*/ /* Free self and subcontractor list, but NOT the subcontractors. There is a potential problem: what if someone holds a pointer to us? Some going out of business notification would be necessary in that case. Most subclasses lock out free so this is not an immediate problem */ - free { [MiscCoordConverter unregisterSubcontractor:self]; [services free]; return [self free]; } /*===========================================================================*/ /* Service support methods */ /*===========================================================================*/ /* For subclass use: add a service to our list of conversion services. */ - addService: (SEL) aSelector convertsFrom: (Class) one to: (Class) two { struct __MiscService theService; if (!services) services = [[Storage allocFromZone:[self zone]] initCount: 0 elementSize: MISC_SERVICE_SIZE description: MISC_SERVICE_DESCRIPTION]; theService.iClass = one; theService.oClass = two; theService.xlator = aSelector; [services addElement: (void*) &theService]; return self; } /*---------------------------------------------------------------------------*/ /* Internal method to search for a service in our list of conversion services. We return the selector that can carry out the desired conversion, or else a null selector if we cannot. It is assumed that a null selector will always be undefined. */ - (SEL) findServiceFrom: (Class) one to: (Class) two { struct __MiscService *theService; unsigned int i, cnt = [services count]; for (i=0; i<cnt; i++) { theService = (struct __MiscService *) [services elementAt:i]; if ((theService->iClass == one) && (theService->oClass == two)) return theService->xlator; } return (SEL) 0; } /*===========================================================================*/ /* Basic conversion methods (Internal use only) */ /*===========================================================================*/ /* Collect info we need to carry out the requested job NOTE: Any method that is sent to srcCoord or dstCoord must be in the MiscCoordConverterClient protocol! */ - prepareForJob: inCoord : outCoord { srcConstants = [inCoord constants]; dstConstants = [outCoord constants]; sameConstants = [srcConstants isEqual: dstConstants]; dimensions = [[inCoord class] dimensions]; npoints = [inCoord curBlockSize]; src = [inCoord curPtr]; dst = [outCoord curPtr]; return self; } /*---------------------------------------------------------------------------*/ /* a quick means of copying if data formats are identical. This method is known outside by name, but should never be actually used outside of applyTransform. It will fail if the constants associated with the two MiscCoords are not functionally the same. */ - (BOOL) copyCoords { int len; if (!sameConstants) return NO; len = dimensions * npoints * sizeof(double); bcopy((char*)src, (char*)dst, len); return YES; } /*---------------------------------------------------------------------------*/ /* Apply the specified method to a block of coordinates. Job is set up by prepareForJob: before this method is called. */ - (BOOL) applyTransform:(SEL)aSelector { unsigned int i; /* copy has it's own loop */ if (aSelector == @selector(copyCoords)) [self perform: aSelector]; else for (i=0; i<npoints; i++,dst+=dimensions,src+=dimensions) [self perform: aSelector]; return YES; } /*---------------------------------------------------------------------------*/ /* Conversion setup method. This method sees if we or anyone we know of can handle the requested job. If so, we return YES with local instance vars theTransform and subContractor ready to go. NOTE: If you want to handle conversion between coords of different dimensionality, look here first. Both MiscCoords must: 1) Conform to the MiscCoordConverterClient protocol. 2) Have the same dimensionality. 3) Have the same transfer blocksize pre-set to the same size. 4) Some Converter object must be willing to accept the job of converting or copying between the two types. */ - (BOOL) reviewSpecification: inCoord to: outCoord { unsigned int i; Class srcClass, dstClass; BOOL srcOk,dstOk; srcClass = [inCoord class]; dstClass = [outCoord class]; srcOk = [srcClass conformsTo:@protocol(MiscCoordConverterClient)]; dstOk = [dstClass conformsTo:@protocol(MiscCoordConverterClient)]; if (!(srcOk && dstOk)) return NO; if ([srcClass dimensions] != [dstClass dimensions]) return NO; if ([inCoord curBlockSize] != [outCoord curBlockSize]) return NO; /* We should be able to handle it ourselves most of the time, or else the customer has the wrong delegate! */ if (theTransform = [self findServiceFrom: srcClass to: dstClass]) aSubcontractor = self; else /* If we can't do it ourselves, try subcontracting to one of the other registered convertors */ for (i=0; aSubcontractor = [MiscCoordConverter getSubcontractor:i]; i++) {if (aSubcontractor == self) continue; if (theTransform = [aSubcontractor findServiceFrom: srcClass to: dstClass]) break; } return ((theTransform) ? YES : NO); } /*===========================================================================*/ /* Misc Coord Converter Server protocol */ /*===========================================================================*/ /* Convert the specified block of coordinates from the source type to the destination type if we are able, or if we can subcontract it to someone else who is able to do it. If there is any reason at all that we cannot, then return NO. DESIGN NOTE: Although local methods are executing, there may be one OR two different objects with private storage involved. Care must be taken to make sure that setup takes place in the correct object, ie usually the subcontractor object. The subcontractor will often be self, in which case setting ivars in this method would work: but if not, the subcontractor would probably crash because things would not be set up in ITS' ivars. THINK before making changes to where set up occurs! */ - (BOOL) convert: inCoord to: outCoord { if (![self reviewSpecification: inCoord to: outCoord]) return NO; [aSubcontractor prepareForJob: inCoord : outCoord]; return [aSubcontractor applyTransform:theTransform]; } /*===========================================================================*/ /* For Subclass use: We have a fast means of copying, but there is no need to make it really public. To discourage possibly disastrous attempts to use it directly, we supply a means of getting it's selector for use in an addService method by a subclass. */ - (SEL) fastCopySelector {return (@selector(copyCoords));} /*===========================================================================*/ /* Archive methods */ /*===========================================================================*/ /* This class should not be used on its own. Presumably a subclass will re-generate it's services list when it awakes, or if it is a single instance class, it will just delete this object when it answers with a finishUnarchiving message. */ - awake { [super awake]; services = nil; [MiscCoordConverter registerSubcontractor: self]; return self; } @end
These are the contents of the former NiCE NeXT User Group NeXTSTEP/OpenStep software archive, currently hosted by Netfuture.ch.