AutoCAD C++ When AcDbEntity need to open for read? - c++

I’m not sure when open entities for read is necessary, and when it may be omit.
For example I know I don’t need to open entity when I want to use objectId() but there are some methods which require to open entity before.
I don’t know if it’s necessary to open AcDbPolyline before getArcSegAt(). In many cases I can simple try to use method before it’s open I will get what I want or not. But maybe there is some easy rule for that?
Example:
AcDbObjectId id = somethingNotImportant();
AcDbPolyline* _pPoly = NULL;
if (id.isValid())
{
AcDbEntity* pEnt = NULL;
Acad::ErrorStatus es;
es = acdbOpenObject(pEnt, id, AcDb::kForRead);
if( es == Acad::eOk)
{
if(pEnt->isKindOf(AcDbPolyline::desc()))
{
this->_pPoly = AcDbPolyline::cast(pEnt);
}
es = pEnt->close();
}
}
now _pPoly is initiallized , but it is closed because of pEnt->close();
now I want for example use:
AcGePoint3d Px = initializedSomehow();
double distAtPx = 0;
_pPoly->getDistAtPoint(Px , distAtPx);
do I need to :
es = acdbOpenObject(_pPoly, id, AcDb::kForRead);
before:
_pPoly->getDistAtPoint(Px , distAtPx);

I would consider it good practise to use the appropriate read access on your object first. That way you are guaranteed to know if you are only able to read the entity or also write to the entity.
This way you are in control. If you just go ahead and use the entity you have no way of knowing in the underlying library changes it's default behaviour.
Sorry if this does not answer your question.

I've looked in the documentation, and I'm not seeing anything that indicates anything about being able to use methods on a closed object. I expect that the assumption is that to work with any real AutoCAD data requires the object to be open for at least reading.
In that case, there are two ways to improve upon your example.
First option: do the work before closing the object. This keeps the open/close code all together with the work being done in the middle. This is nice that it should be clear when the object is open and can be worked with and that the object is not left open. This also meets the recommendation in the documentation to not keep object open any longer than necessary.
AcGePoint3d Px = initializedSomehow();
double distAtPx = 0;
AcDbObjectId id = somethingNotImportant();
if (id.isValid())
{
AcDbEntity* pEnt = NULL;
Acad::ErrorStatus es;
es = acdbOpenObject(pEnt, id, AcDb::kForRead);
if( es == Acad::eOk)
{
if(pEnt->isKindOf(AcDbPolyline::desc()))
{
AcDbPolyline*_pPoly = AcDbPolyline::cast(pEnt);
//Do work with poly here
_pPoly->getDistAtPoint(Px , distAtPx);
}
es = pEnt->close();
}
}
Second option: close the object only after doing the work, and only if the object is the right type. This allows for non-local usage of the opened object, but you need to make sure you close it later!
AcDbObjectId id = somethingNotImportant();
AcDbPolyline* _pPoly = NULL;
if (id.isValid())
{
AcDbEntity* pEnt = NULL;
Acad::ErrorStatus es;
es = acdbOpenObject(pEnt, id, AcDb::kForRead);
if( es == Acad::eOk)
{
if(pEnt->isKindOf(AcDbPolyline::desc()))
{
_pPoly = AcDbPolyline::cast(pEnt);
}
else
es = pEnt->close(); //not polyline, close now
}
}
AcGePoint3d Px = initializedSomehow();
double distAtPx = 0;
if (_pPoly)
{
//Do work with poly here
_pPoly->getDistAtPoint(Px , distAtPx);
_pPoly->close();
}

Related

Converting an unruly dependency injection model with a service locator

I've been using DI for a game engine project for a while and I just hit a wall; given the below order of creation: The job system does not depend on anything and everything depends on the file logger. It makes sense to create the job system, then the file logger, then pass the created references for each dependency down to its dependents' constructors.
App::App(const std::string& cmdString)
: EngineSubsystem()
, _theJobSystem{std::make_unique<JobSystem>(-1, static_cast<std::size_t>(JobType::Max), new std::condition_variable)}
, _theFileLogger{std::make_unique<FileLogger>(*_theJobSystem.get(), "game")}
, _theConfig{std::make_unique<Config>(KeyValueParser{cmdString})}
, _theRenderer{std::make_unique<Renderer>(*_theJobSystem.get(), *_theFileLogger.get(), *_theConfig.get())}
, _theInputSystem{std::make_unique<InputSystem>(*_theFileLogger.get(), *_theRenderer.get())}
, _theUI{std::make_unique<UISystem>(*_theFileLogger.get(), *_theRenderer.get(), *_theInputSystem.get())}
, _theConsole{std::make_unique<Console>(*_theFileLogger.get(), *_theRenderer.get())}
, _theAudioSystem{std::make_unique<AudioSystem>(*_theFileLogger.get()) }
, _theGame{std::make_unique<Game>()}
{
SetupEngineSystemPointers();
SetupEngineSystemChainOfResponsibility();
LogSystemDescription();
}
void App::SetupEngineSystemPointers() {
g_theJobSystem = _theJobSystem.get();
g_theFileLogger = _theFileLogger.get();
g_theConfig = _theConfig.get();
g_theRenderer = _theRenderer.get();
g_theUISystem = _theUI.get();
g_theConsole = _theConsole.get();
g_theInputSystem = _theInputSystem.get();
g_theAudioSystem = _theAudioSystem.get();
g_theGame = _theGame.get();
g_theApp = this;
}
void App::SetupEngineSystemChainOfResponsibility() {
g_theConsole->SetNextHandler(g_theUISystem);
g_theUISystem->SetNextHandler(g_theInputSystem);
g_theInputSystem->SetNextHandler(g_theApp);
g_theApp->SetNextHandler(nullptr);
g_theSubsystemHead = g_theConsole;
}
As you can see, passing the different subsystems around to the other subsystem constructors is starting to get messy. In particular when dealing with jobs, logging, console commands, UI, configuration, and audio (and physics, not pictured).
(Side note: These are going to eventually be replaced with interfaces created via factories for cross-compatibility, i.e. the Renderer is strictly a DirectX/Windows-only renderer but I want to eventually support OpenGL/Linux; that's why everything is passed around as references and created as pointers instead of a concrete types)
I've run in to situations where pretty much all the subsystems are in some way dependent on every other subsystem.
But, due to construction-order problems, Dependency Injection does not work because one or more of the required-to-exist subsystems hasn't been constructed yet. Same problem with two-phase construction: the subsystem may not have been initialized by the time it's needed further downstream.
I looked in to the service locator pattern and this question deems it a bad idea, but the game industry likes using bad ideas (like global variables to every subsystem for game-specific code to use) if they work.
Would converting to a service locator fix this problem?
What other implementations do you know of that could also fix the issue?
I ultimately went with the ServiceLocator pattern, deriving every subsystem that was a dependency as a Service:
App::App(const std::string& cmdString)
: EngineSubsystem()
, _theConfig{std::make_unique<Config>(KeyValueParser{cmdString})}
{
SetupEngineSystemPointers();
SetupEngineSystemChainOfResponsibility();
LogSystemDescription();
}
void App::SetupEngineSystemPointers() {
ServiceLocator::provide(*static_cast<IConfigService*>(_theConfig.get()));
_theJobSystem = std::make_unique<JobSystem>(-1, static_cast<std::size_t>(JobType::Max), new std::condition_variable);
ServiceLocator::provide(*static_cast<IJobSystemService*>(_theJobSystem.get()));
_theFileLogger = std::make_unique<FileLogger>("game");
ServiceLocator::provide(*static_cast<IFileLoggerService*>(_theFileLogger.get()));
_theRenderer = std::make_unique<Renderer>();
ServiceLocator::provide(*static_cast<IRendererService*>(_theRenderer.get()));
_theInputSystem = std::make_unique<InputSystem>();
ServiceLocator::provide(*static_cast<IInputService*>(_theInputSystem.get()));
_theAudioSystem = std::make_unique<AudioSystem>();
ServiceLocator::provide(*static_cast<IAudioService*>(_theAudioSystem.get()));
_theUI = std::make_unique<UISystem>();
_theConsole = std::make_unique<Console>();
_theGame = std::make_unique<Game>();
g_theJobSystem = _theJobSystem.get();
g_theFileLogger = _theFileLogger.get();
g_theConfig = _theConfig.get();
g_theRenderer = _theRenderer.get();
g_theUISystem = _theUI.get();
g_theConsole = _theConsole.get();
g_theInputSystem = _theInputSystem.get();
g_theAudioSystem = _theAudioSystem.get();
g_theGame = _theGame.get();
g_theApp = this;
}
void App::SetupEngineSystemChainOfResponsibility() {
g_theConsole->SetNextHandler(g_theUISystem);
g_theUISystem->SetNextHandler(g_theInputSystem);
g_theInputSystem->SetNextHandler(g_theRenderer);
g_theRenderer->SetNextHandler(g_theApp);
g_theApp->SetNextHandler(nullptr);
g_theSubsystemHead = g_theConsole;
}

Trouble creating pointer to abstract class

I coded some smiley faces into my app recently, but I'm having trouble calling it in my option interface. The reason I'm wanting to call it from optioninterface is I want to add 2 sets of emojis, and if the value of Setting.nEmoji is 0 or 1 call a different set. The function loademojis() gets called when the application starts (it's technically coded in the interface solution). I can call it from a function that handles user input, but it generated horrible lag, I assume because each time a letter was typed, it cleared the array and loaded the emojis in again. So long story short, I was wondering if there's any way at all to create a pointer to a abstract class so I could call this from my option menu. Everytime I create a pointer and call it from theoption menu it crashes. Here's how I'm creating the pointer
MDrawContext* pDC
void MDrawContext::LoadEmojis()
{
if (Z_VIDEO_EMOJIS == 1)
{
m_Emoji[";)"] = "wink.png";
m_Emoji[":)"] = "smile.png";
m_Emoji[":D"] = "biggrin.png";
m_Emoji[":("] = "frown.png";
m_Emoji[":O"] = "eek.png";
m_Emoji[":P"] = "tongue.png";
m_Emoji[":?"] = "confused.png";
m_Emoji[":4"] = "cool.png";
m_Emoji[":3"] = "redface.png";
m_Emoji[":#"] = "mad.png";
m_Emoji[":I"] = "rolleyes.png";
m_Emoji[":K"] = "kappa.png";
}
else
{
m_Emoji[";)"] = "wink2.png";
m_Emoji[":)"] = "smile2.png";
m_Emoji[":D"] = "biggrin2.png";
m_Emoji[":("] = "frown2.png";
m_Emoji[":O"] = "eek2.png";
m_Emoji[":P"] = "tongue2.png";
}
}
//custom: reloademojis allows players to choose between ios/forum emojis
void MDrawContext::ReloadEmojis()
{
m_Emoji[";)"].clear();
m_Emoji[":)"].clear();
m_Emoji[":D"].clear();
m_Emoji[":("].clear();
m_Emoji[":O"].clear();
m_Emoji[":P"].clear();
m_Emoji[":?"].clear();
m_Emoji[":4"].clear();
m_Emoji[":3"].clear();
m_Emoji[":#"].clear();
m_Emoji[":I"].clear();
m_Emoji[":K"].clear();
LoadEmojis();
}
//Calling the pointer (different cpp)
int nEmojiType = 0;
if(nEmojiType != Z_VIDEO_EMOJI)
{
pDC->ReloadEmojis();
nEmojiType = Z_VIDEO_EMOJI;
}

Extract polygons from shapefile using Geotools

I have a shape file (Sample.shp) along with two other files (Sample.shx and Sample.dbf), which has geometry (polygons) defined for 15 pincodes of Bombay.
I am able to view the .shp file using the Quickstart tutorial.
File file = JFileDataStoreChooser.showOpenFile("shp", null);
if (file == null) {
return;
}
FileDataStore store = FileDataStoreFinder.getDataStore(file);
SimpleFeatureSource featureSource = store.getFeatureSource();
// Create a map content and add our shapefile to it
MapContent map = new MapContent();
map.setTitle("Quickstart");
Style style = SLD.createSimpleStyle(featureSource.getSchema());
Layer layer = new FeatureLayer(featureSource, style);
map.addLayer(layer);
// Now display the map
JMapFrame.showMap(map);
Now I want to convert the geometry of these 15 pincodes to 15 Geometry/Polygon objects so that I can use Geometry.contains() to find if a point falls in a particular Geometry/Polygon.
I tried:
ShapefileReader r = new ShapefileReader(new ShpFiles(file),true,false,geometryFactory);
System.out.println(r.getCount(0)); >> returns 51
System.out.println(r.hasNext()); >> returns false
Any help is really appreciated
In fact you don't need to extract the geometries your self - just create a filter and iterate through the filtered collection. In your case there will probably be only one feature returned.
Filter pointInPolygon = CQL.toFilter("CONTAINS(the_geom, POINT(1 2))");
SimpleFeatureCollection features = source.getFeatures(filter);
SimpleFeatureIterator iterator = features.features();
try {
while (iterator.hasNext()) {
SimpleFeature feature = iterator.next();
Geometry geom = (Geometry) feature.getDefaultGeometry();
/*... do something here */
}
} finally {
iterator.close(); // IMPORTANT
}
For a full discussion of querying datastores see the Query Lab.
I used the above solution and tried a few combinations. Just changed "THE_GEOM" to lower case and POINT is in order (Lon Lat)
Filter filter = CQL.toFilter("CONTAINS(the_geom, POINT(72.82916 18.942883))");
SimpleFeatureCollection collection=featureSource.getFeatures(filter);
SimpleFeatureIterator iterator = collection.features();
try {
while (iterator.hasNext()) {
SimpleFeature feature = iterator.next();
.....
}
} finally {
iterator.close(); // IMPORTANT
}

MediaEngine audio playback on WinRT

I'm trying to add music to my game that runs on WinRT. The music should be in an encoded format (mp3, ogg, etc.) and should be streamable and be decoded by the hardware (for performance reasons).
I've looked through the samples, and found out that MediaEngine can do something like this (I hope).
However, I'm having problems making it work. I keep getting ComExceptions everytime I try to create IMFByteStream from IRandomAccessStream via MFCreateMFByteStreamOnStreamEx().
It might be that I'm not handling tasks correctly, since they are a new paradigm for me.
Here's some code (pretty similar to the sample I mentioned before):
void MyMedia::PlayMusic ()
{
try
{
StorageFolder^ installedLocation = Windows::ApplicationModel::Package::Current->InstalledLocation;
Concurrency::task<StorageFile^> m_pickFileTask = Concurrency::task<StorageFile^>(installedLocation->GetFileAsync("music.mp3"), m_tcs.get_token());
SetURL(StringHelper::toString("music.mp3"));
auto player = this;
m_pickFileTask.then([&player](StorageFile^ fileHandle)
{
Concurrency::task<IRandomAccessStream^> fOpenStreamTask = Concurrency::task<IRandomAccessStream^> (fileHandle->OpenAsync(Windows::Storage::FileAccessMode::Read));
fOpenStreamTask.then([&player](IRandomAccessStream^ streamHandle)
{
try
{
player->SetBytestream(streamHandle);
if (player->m_spMediaEngine)
{
MEDIA::ThrowIfFailed(
player->m_spMediaEngine->Play()
);
}
} catch(Platform::Exception^)
{
MEDIA::ThrowIfFailed(E_UNEXPECTED);
}
}
);
}
);
} catch(Platform::Exception^ ex)
{
Printf("error: %s", ex->Message);
}
}
void MyMedia::SetBytestream(IRandomAccessStream^ streamHandle)
{
HRESULT hr = S_OK;
ComPtr<IMFByteStream> spMFByteStream = nullptr;
//The following line always throws a ComException
MEDIA::ThrowIfFailed(
MFCreateMFByteStreamOnStreamEx((IUnknown*)streamHandle, &spMFByteStream)
);
MEDIA::ThrowIfFailed(
m_spEngineEx->SetSourceFromByteStream(spMFByteStream.Get(), m_bstrURL)
);
return;
}
Bonus: If you know a better solution to my audio needs, please leave a comment.
I managed to fix this. There was two problems I found.
Media Foundation was not initialized
MFStartup(MF_VERSION); needs to be called before Media Foundation can be used. I added this code just before creating the media engine.
Referencing a pointer.
Line m_pickFileTask.then([&player](StorageFile^ fileHandle) should be m_pickFileTask.then([player](StorageFile^ fileHandle). This is already a pointer to the current class, and & provides the address of variable, so I was actually passing the pointer's pointer.

Windows Phone 7 Consuming Webservice WSDL

Ok I have written some basic generic webservices before but I have never tried to consume a 3rd party one.
The one I am trying to consume is
http://opendap.co-ops.nos.noaa.gov/axis/webservices/predictions/wsdl/Predictions.wsdl
I am not getting any results back from this what so ever and cannot figure out why.
More odd is it is not even reaching PredictionsClient_getPredictionsAndMetadataCompleted when I put a break point in the code it doesn't even reach it.
Any suggestions would be greatly appreciated
public void Bouy(double meters)
{
PredictionService.Parameters PredictionParams = new PredictionService.Parameters();
PredictionService.PredictionsPortTypeClient PredictionsClient = new PredictionService.PredictionsPortTypeClient();
GeoCoordinateWatcher gc = new GeoCoordinateWatcher(GeoPositionAccuracy.Default);
//gc.Position.Location.Latitude, gc.Position.Location.Longitude
GeoCoordinate myLocation = new GeoCoordinate(27.931631,-82.802582);
foreach (var bl in BouyLocation.GetAll())
{
GeoCoordinate otherLocation = new GeoCoordinate(bl.Lat, bl.Lon);
PredictionParams.beginDate = DateTime.Now.ToString("yyyyMMdd");
PredictionParams.endDate = DateTime.Now.AddDays(1.0).ToString("yyyyMMdd");
PredictionParams.stationId = bl.LocationID;
PredictionParams.timeZone = 0;
PredictionParams.unit = 1;
PredictionParams.dataInterval = 6;
PredictionsClient.getPredictionsAndMetadataCompleted += new EventHandler<PredictionService.getPredictionsAndMetadataCompletedEventArgs>(PredictionsClient_getPredictionsAndMetadataCompleted);
PredictionsClient.getPredictionsAndMetadataAsync(PredictionParams);
double mymeters = myLocation.GetDistanceTo(otherLocation);
if (mymeters < meters)
{
TextBlock DynTextBlock = new TextBlock
{
Name = "Appearance" + bl.LocationID,
Text = bl.LocationName + PredictionResult,
TextWrapping = System.Windows.TextWrapping.Wrap,
Margin = new Thickness(12, -6, 12, 0),
Style = (Style)Resources["PhoneTextSubtleStyle"]
};
DynamicAppearance.Children.Add(DynTextBlock);
this.nearByLocations.Add(new BouyLocationModel() { LocationName = bl.LocationName, LocationID = bl.LocationID, Lat = bl.Lat, Lon = bl.Lon });
}
}
var test = nearByLocations;
}
void PredictionsClient_getPredictionsAndMetadataCompleted(object sender, PredictionService.getPredictionsAndMetadataCompletedEventArgs e)
{
string err = e.Error.ToString();
PredictionResult = e.Result.ToString();
}
Loooking at the code you have here I think that you have used the importing of a ServiceReference to auto build the classes for you?
Unfortunately I have found that this is rather temperamental on WP7 and the only way I actually got it to work was when I connected it to a Microsoft WCF service. Connecting to anything else just doesn't work.
If you do google searches there are various pages talking about the fact it doesn't work and ways around it (which I couldn't get to work).
However, there are ways around it but it isn't as simple as the auto-generated stuff. Basically you do things manually.
Although there are other ways to manually create the web service what I did was follow the information in the following which worked well: http://zetitle.wordpress.com/2010/10/14/using-reactive-extensions-with-webrequest/
You will need to parse the response yourself but XML to LINQ works really well for this.
Hope that helps, or maybe someone will have the solution as it is something I am interested in knowing how to get working too