<commit_before>// Copyright (c) 2012 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.

#include "chrome/browser/pepper_broker_infobar_delegate.h"

#include "base/prefs/pref_service.h"
#include "chrome/browser/api/infobars/infobar_service.h"
#include "chrome/browser/content_settings/host_content_settings_map.h"
#include "chrome/browser/content_settings/tab_specific_content_settings.h"
#include "chrome/browser/plugins/plugin_finder.h"
#include "chrome/browser/plugins/plugin_metadata.h"
#include "chrome/browser/profiles/profile.h"
#include "chrome/common/pref_names.h"
#include "content/public/browser/page_navigator.h"
#include "content/public/browser/plugin_service.h"
#include "content/public/browser/user_metrics.h"
#include "content/public/browser/web_contents.h"
#include "content/public/common/referrer.h"
#include "grit/generated_resources.h"
#include "grit/theme_resources.h"
#include "net/base/net_util.h"
#include "ui/base/l10n/l10n_util.h"
#include "ui/base/resource/resource_bundle.h"
#include "webkit/plugins/webplugininfo.h"

// The URL for the "learn more" article about the PPAPI broker.
const char kPpapiBrokerLearnMoreUrl[] =
    "https://support.google.com/chrome/?p=ib_pepper_broker";

using content::OpenURLParams;
using content::Referrer;
using content::WebContents;

// static
void PepperBrokerInfoBarDelegate::Create(
    WebContents* web_contents,
    const GURL& url,
    const base::FilePath& plugin_path,
    const base::Callback<void(bool)>& callback) {
  Profile* profile =
      Profile::FromBrowserContext(web_contents->GetBrowserContext());
  // TODO(wad): Add ephemeral device ID support for broker in guest mode.
  if (profile->IsGuestSession()) {
    callback.Run(false);
    return;
  }

  TabSpecificContentSettings* tab_content_settings =
      TabSpecificContentSettings::FromWebContents(web_contents);
  HostContentSettingsMap* content_settings =
      profile->GetHostContentSettingsMap();
  ContentSetting setting =
      content_settings->GetContentSetting(url, url,
                                          CONTENT_SETTINGS_TYPE_PPAPI_BROKER,
                                          std::string());
  switch (setting) {
    case CONTENT_SETTING_ALLOW: {
      content::RecordAction(
          content::UserMetricsAction("PPAPI.BrokerSettingAllow"));
      tab_content_settings->SetPepperBrokerAllowed(true);
      callback.Run(true);
      break;
    }
    case CONTENT_SETTING_BLOCK: {
      content::RecordAction(
          content::UserMetricsAction("PPAPI.BrokerSettingDeny"));
      tab_content_settings->SetPepperBrokerAllowed(false);
      callback.Run(false);
      break;
    }
    case CONTENT_SETTING_ASK: {
      content::RecordAction(
          content::UserMetricsAction("PPAPI.BrokerInfobarDisplayed"));

      InfoBarService* infobar_service =
          InfoBarService::FromWebContents(web_contents);
      std::string languages =
          profile->GetPrefs()->GetString(prefs::kAcceptLanguages);
      infobar_service->AddInfoBar(scoped_ptr<InfoBarDelegate>(
          new PepperBrokerInfoBarDelegate(
              infobar_service, url, plugin_path, languages, content_settings,
              tab_content_settings, callback)));
      break;
    }
    default:
      NOTREACHED();
  }
}

string16 PepperBrokerInfoBarDelegate::GetMessageText() const {
  content::PluginService* plugin_service =
      content::PluginService::GetInstance();
  webkit::WebPluginInfo plugin;
  bool success = plugin_service->GetPluginInfoByPath(plugin_path_, &plugin);
  DCHECK(success);
  scoped_ptr<PluginMetadata> plugin_metadata(
      PluginFinder::GetInstance()->GetPluginMetadata(plugin));
  return l10n_util::GetStringFUTF16(IDS_PEPPER_BROKER_MESSAGE,
                                    plugin_metadata->name(),
                                    net::FormatUrl(url_.GetOrigin(),
                                                   languages_));
}

int PepperBrokerInfoBarDelegate::GetButtons() const {
  return BUTTON_OK | BUTTON_CANCEL;
}

string16 PepperBrokerInfoBarDelegate::GetButtonLabel(
    InfoBarButton button) const {
  switch (button) {
    case BUTTON_OK:
      return l10n_util::GetStringUTF16(IDS_PEPPER_BROKER_ALLOW_BUTTON);
    case BUTTON_CANCEL:
      return l10n_util::GetStringUTF16(IDS_PEPPER_BROKER_DENY_BUTTON);
    default:
      NOTREACHED();
      return string16();
  }
}

bool PepperBrokerInfoBarDelegate::Accept() {
  DispatchCallback(true);
  return true;
}

bool PepperBrokerInfoBarDelegate::Cancel() {
  DispatchCallback(false);
  return true;
}

string16 PepperBrokerInfoBarDelegate::GetLinkText() const {
  return l10n_util::GetStringUTF16(IDS_LEARN_MORE);
}

bool PepperBrokerInfoBarDelegate::LinkClicked(
    WindowOpenDisposition disposition) {
  OpenURLParams params(
      GURL(kPpapiBrokerLearnMoreUrl), Referrer(),
      (disposition == CURRENT_TAB) ? NEW_FOREGROUND_TAB : disposition,
      content::PAGE_TRANSITION_LINK,
      false);
  owner()->GetWebContents()->OpenURL(params);
  return false;
}

gfx::Image* PepperBrokerInfoBarDelegate::GetIcon() const {
  return &ResourceBundle::GetSharedInstance().GetNativeImageNamed(
      IDR_INFOBAR_PLUGIN_INSTALL);
}

PepperBrokerInfoBarDelegate::PepperBrokerInfoBarDelegate(
    InfoBarService* infobar_service,
    const GURL& url,
    const base::FilePath& plugin_path,
    const std::string& languages,
    HostContentSettingsMap* content_settings,
    TabSpecificContentSettings* tab_content_settings,
    const base::Callback<void(bool)>& callback)
    : ConfirmInfoBarDelegate(infobar_service),
      url_(url),
      plugin_path_(plugin_path),
      languages_(languages),
      content_settings_(content_settings),
      tab_content_settings_(tab_content_settings),
      callback_(callback) {
}

PepperBrokerInfoBarDelegate::~PepperBrokerInfoBarDelegate() {
  if (!callback_.is_null())
    callback_.Run(false);
}

void PepperBrokerInfoBarDelegate::DispatchCallback(bool result) {
  content::RecordAction(result ?
      content::UserMetricsAction("PPAPI.BrokerInfobarClickedAllow") :
      content::UserMetricsAction("PPAPI.BrokerInfobarClickedDeny"));
  callback_.Run(result);
  callback_ = base::Callback<void(bool)>();
  content_settings_->SetContentSetting(
      ContentSettingsPattern::FromURLNoWildcard(url_),
      ContentSettingsPattern::Wildcard(),
      CONTENT_SETTINGS_TYPE_PPAPI_BROKER,
      std::string(), result ? CONTENT_SETTING_ALLOW : CONTENT_SETTING_BLOCK);
  tab_content_settings_->SetPepperBrokerAllowed(result);
}
<commit_msg>Disabled plugin broker infobar on Chrome OS for Netflix since this plugins can only come installed by the OS.<commit_after>// Copyright (c) 2012 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.

#include "chrome/browser/pepper_broker_infobar_delegate.h"

#include "base/prefs/pref_service.h"
#include "chrome/browser/api/infobars/infobar_service.h"
#include "chrome/browser/content_settings/host_content_settings_map.h"
#include "chrome/browser/content_settings/tab_specific_content_settings.h"
#include "chrome/browser/plugins/plugin_finder.h"
#include "chrome/browser/plugins/plugin_metadata.h"
#include "chrome/browser/profiles/profile.h"
#include "chrome/common/pref_names.h"
#include "content/public/browser/page_navigator.h"
#include "content/public/browser/plugin_service.h"
#include "content/public/browser/user_metrics.h"
#include "content/public/browser/web_contents.h"
#include "content/public/common/referrer.h"
#include "grit/generated_resources.h"
#include "grit/theme_resources.h"
#include "net/base/net_util.h"
#include "ui/base/l10n/l10n_util.h"
#include "ui/base/resource/resource_bundle.h"
#include "webkit/plugins/webplugininfo.h"

// The URL for the "learn more" article about the PPAPI broker.
const char kPpapiBrokerLearnMoreUrl[] =
    "https://support.google.com/chrome/?p=ib_pepper_broker";

#if defined(OS_CHROMEOS)
const char kNetflixPluginFileName[] = "libnetflixplugin2.so";
#endif

using content::OpenURLParams;
using content::Referrer;
using content::WebContents;

// static
void PepperBrokerInfoBarDelegate::Create(
    WebContents* web_contents,
    const GURL& url,
    const base::FilePath& plugin_path,
    const base::Callback<void(bool)>& callback) {
  Profile* profile =
      Profile::FromBrowserContext(web_contents->GetBrowserContext());
  // TODO(wad): Add ephemeral device ID support for broker in guest mode.
  if (profile->IsGuestSession()) {
    callback.Run(false);
    return;
  }

  TabSpecificContentSettings* tab_content_settings =
      TabSpecificContentSettings::FromWebContents(web_contents);

#if defined(OS_CHROMEOS)
  // On ChromeOS, we're ok with granting broker access to Netflix plugin, since
  // it can only come installed with the OS.
  if (plugin_path.BaseName().value() ==
          FILE_PATH_LITERAL(kNetflixPluginFileName)) {
    tab_content_settings->SetPepperBrokerAllowed(true);
    callback.Run(true);
    return;
  }
#endif

  HostContentSettingsMap* content_settings =
      profile->GetHostContentSettingsMap();
  ContentSetting setting =
      content_settings->GetContentSetting(url, url,
                                          CONTENT_SETTINGS_TYPE_PPAPI_BROKER,
                                          std::string());
  switch (setting) {
    case CONTENT_SETTING_ALLOW: {
      content::RecordAction(
          content::UserMetricsAction("PPAPI.BrokerSettingAllow"));
      tab_content_settings->SetPepperBrokerAllowed(true);
      callback.Run(true);
      break;
    }
    case CONTENT_SETTING_BLOCK: {
      content::RecordAction(
          content::UserMetricsAction("PPAPI.BrokerSettingDeny"));
      tab_content_settings->SetPepperBrokerAllowed(false);
      callback.Run(false);
      break;
    }
    case CONTENT_SETTING_ASK: {
      content::RecordAction(
          content::UserMetricsAction("PPAPI.BrokerInfobarDisplayed"));

      InfoBarService* infobar_service =
          InfoBarService::FromWebContents(web_contents);
      std::string languages =
          profile->GetPrefs()->GetString(prefs::kAcceptLanguages);
      infobar_service->AddInfoBar(scoped_ptr<InfoBarDelegate>(
          new PepperBrokerInfoBarDelegate(
              infobar_service, url, plugin_path, languages, content_settings,
              tab_content_settings, callback)));
      break;
    }
    default:
      NOTREACHED();
  }
}

string16 PepperBrokerInfoBarDelegate::GetMessageText() const {
  content::PluginService* plugin_service =
      content::PluginService::GetInstance();
  webkit::WebPluginInfo plugin;
  bool success = plugin_service->GetPluginInfoByPath(plugin_path_, &plugin);
  DCHECK(success);
  scoped_ptr<PluginMetadata> plugin_metadata(
      PluginFinder::GetInstance()->GetPluginMetadata(plugin));
  return l10n_util::GetStringFUTF16(IDS_PEPPER_BROKER_MESSAGE,
                                    plugin_metadata->name(),
                                    net::FormatUrl(url_.GetOrigin(),
                                                   languages_));
}

int PepperBrokerInfoBarDelegate::GetButtons() const {
  return BUTTON_OK | BUTTON_CANCEL;
}

string16 PepperBrokerInfoBarDelegate::GetButtonLabel(
    InfoBarButton button) const {
  switch (button) {
    case BUTTON_OK:
      return l10n_util::GetStringUTF16(IDS_PEPPER_BROKER_ALLOW_BUTTON);
    case BUTTON_CANCEL:
      return l10n_util::GetStringUTF16(IDS_PEPPER_BROKER_DENY_BUTTON);
    default:
      NOTREACHED();
      return string16();
  }
}

bool PepperBrokerInfoBarDelegate::Accept() {
  DispatchCallback(true);
  return true;
}

bool PepperBrokerInfoBarDelegate::Cancel() {
  DispatchCallback(false);
  return true;
}

string16 PepperBrokerInfoBarDelegate::GetLinkText() const {
  return l10n_util::GetStringUTF16(IDS_LEARN_MORE);
}

bool PepperBrokerInfoBarDelegate::LinkClicked(
    WindowOpenDisposition disposition) {
  OpenURLParams params(
      GURL(kPpapiBrokerLearnMoreUrl), Referrer(),
      (disposition == CURRENT_TAB) ? NEW_FOREGROUND_TAB : disposition,
      content::PAGE_TRANSITION_LINK,
      false);
  owner()->GetWebContents()->OpenURL(params);
  return false;
}

gfx::Image* PepperBrokerInfoBarDelegate::GetIcon() const {
  return &ResourceBundle::GetSharedInstance().GetNativeImageNamed(
      IDR_INFOBAR_PLUGIN_INSTALL);
}

PepperBrokerInfoBarDelegate::PepperBrokerInfoBarDelegate(
    InfoBarService* infobar_service,
    const GURL& url,
    const base::FilePath& plugin_path,
    const std::string& languages,
    HostContentSettingsMap* content_settings,
    TabSpecificContentSettings* tab_content_settings,
    const base::Callback<void(bool)>& callback)
    : ConfirmInfoBarDelegate(infobar_service),
      url_(url),
      plugin_path_(plugin_path),
      languages_(languages),
      content_settings_(content_settings),
      tab_content_settings_(tab_content_settings),
      callback_(callback) {
}

PepperBrokerInfoBarDelegate::~PepperBrokerInfoBarDelegate() {
  if (!callback_.is_null())
    callback_.Run(false);
}

void PepperBrokerInfoBarDelegate::DispatchCallback(bool result) {
  content::RecordAction(result ?
      content::UserMetricsAction("PPAPI.BrokerInfobarClickedAllow") :
      content::UserMetricsAction("PPAPI.BrokerInfobarClickedDeny"));
  callback_.Run(result);
  callback_ = base::Callback<void(bool)>();
  content_settings_->SetContentSetting(
      ContentSettingsPattern::FromURLNoWildcard(url_),
      ContentSettingsPattern::Wildcard(),
      CONTENT_SETTINGS_TYPE_PPAPI_BROKER,
      std::string(), result ? CONTENT_SETTING_ALLOW : CONTENT_SETTING_BLOCK);
  tab_content_settings_->SetPepperBrokerAllowed(result);
}
<|endoftext|>


<commit_before>// [WriteFile Name=FeatureLayerShapefile, Category=Layers]
// [Legal]
// Copyright 2017 Esri.

// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
// http://www.apache.org/licenses/LICENSE-2.0

// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
// [Legal]

#include "FeatureLayerShapefile.h"

#include "Map.h"
#include "MapQuickView.h"
#include "Basemap.h"
#include "ShapefileFeatureTable.h"
#include "FeatureLayer.h"

#include <QQmlProperty>

using namespace Esri::ArcGISRuntime;

FeatureLayerShapefile::FeatureLayerShapefile(QQuickItem* parent /* = nullptr */):
    QQuickItem(parent)
{
}

void FeatureLayerShapefile::init()
{
    // Register the map view for QML
    qmlRegisterType<MapQuickView>("Esri.Samples", 1, 0, "MapView");
    qmlRegisterType<FeatureLayerShapefile>("Esri.Samples", 1, 0, "FeatureLayerShapefileSample");
}

void FeatureLayerShapefile::componentComplete()
{
    QQuickItem::componentComplete();

    QString dataPath = QQmlProperty::read(this, "dataPath").toString();

    // find QML MapView component
    m_mapView = findChild<MapQuickView*>("mapView");

    // Create a map using the topographic basemap
     m_map = new Map(Basemap::streetsVector(this), this);

    // Set map to map view
    m_mapView->setMap(m_map);

    // Create and add the shapefile to the map
    createAndAddShapefileLayer(dataPath + "Public_Art.shp");
}
void FeatureLayerShapefile::createAndAddShapefileLayer(QUrl const &file)
{

    QString dataPath = file.toLocalFile();

    // Create the ShapefileFeatureTable
    ShapefileFeatureTable* featureTable = new ShapefileFeatureTable(dataPath, this);

    // Create the feature layer from the ShapefileFeatureTable
    FeatureLayer* layer = new FeatureLayer(featureTable, this);

    connect(layer, &FeatureLayer::doneLoading, this, [this, layer](Error loadError)
    {
        if (!loadError.isEmpty())
          return;

        // If the layer was loaded successfully, set the map extent to the full extent of the layer
        m_mapView->setViewpointCenter(layer->fullExtent().center(), 80000);
    });

    // Add the shapefile layer to the map
    m_map->operationalLayers()->clear();
    m_map->operationalLayers()->append(layer);
}
<commit_msg>Changed "QUrl const &file" to "const QUrl& file"<commit_after>// [WriteFile Name=FeatureLayerShapefile, Category=Layers]
// [Legal]
// Copyright 2017 Esri.

// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
// http://www.apache.org/licenses/LICENSE-2.0

// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
// [Legal]

#include "FeatureLayerShapefile.h"

#include "Map.h"
#include "MapQuickView.h"
#include "Basemap.h"
#include "ShapefileFeatureTable.h"
#include "FeatureLayer.h"

#include <QQmlProperty>

using namespace Esri::ArcGISRuntime;

FeatureLayerShapefile::FeatureLayerShapefile(QQuickItem* parent /* = nullptr */):
    QQuickItem(parent)
{
}

void FeatureLayerShapefile::init()
{
    // Register the map view for QML
    qmlRegisterType<MapQuickView>("Esri.Samples", 1, 0, "MapView");
    qmlRegisterType<FeatureLayerShapefile>("Esri.Samples", 1, 0, "FeatureLayerShapefileSample");
}

void FeatureLayerShapefile::componentComplete()
{
    QQuickItem::componentComplete();

    QString dataPath = QQmlProperty::read(this, "dataPath").toString();

    // find QML MapView component
    m_mapView = findChild<MapQuickView*>("mapView");

    // Create a map using the topographic basemap
     m_map = new Map(Basemap::streetsVector(this), this);

    // Set map to map view
    m_mapView->setMap(m_map);

    // Create and add the shapefile to the map
    createAndAddShapefileLayer(dataPath + "Public_Art.shp");
}
void FeatureLayerShapefile::createAndAddShapefileLayer(const QUrl& file)
{

    QString dataPath = file.toLocalFile();

    // Create the ShapefileFeatureTable
    ShapefileFeatureTable* featureTable = new ShapefileFeatureTable(dataPath, this);

    // Create the feature layer from the ShapefileFeatureTable
    FeatureLayer* layer = new FeatureLayer(featureTable, this);

    connect(layer, &FeatureLayer::doneLoading, this, [this, layer](Error loadError)
    {
        if (!loadError.isEmpty())
          return;

        // If the layer was loaded successfully, set the map extent to the full extent of the layer
        m_mapView->setViewpointCenter(layer->fullExtent().center(), 80000);
    });

    // Add the shapefile layer to the map
    m_map->operationalLayers()->clear();
    m_map->operationalLayers()->append(layer);
}
<|endoftext|>


<commit_before>// [WriteFile Name=FeatureLayerExtrusion, Category=Scenes]
// [Legal]
// Copyright 2017 Esri.

// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
// http://www.apache.org/licenses/LICENSE-2.0

// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
// [Legal]

#include "FeatureLayerExtrusion.h"

#include "FeatureLayer.h"
#include "ServiceFeatureTable.h"
#include "ArcGISTiledElevationSource.h"
#include "Scene.h"
#include "SceneQuickView.h"
#include "Point.h"
#include "SimpleLineSymbol.h"
#include "SimpleFillSymbol.h"
#include "SimpleRenderer.h"
#include "RendererSceneProperties.h"

using namespace Esri::ArcGISRuntime;

FeatureLayerExtrusion::FeatureLayerExtrusion(QQuickItem* parent /* = nullptr */):
  QQuickItem(parent)
{
}

void FeatureLayerExtrusion::init()
{
  // Register classes for QML
  qmlRegisterType<SceneQuickView>("Esri.Samples", 1, 0, "SceneView");
  qmlRegisterType<FeatureLayerExtrusion>("Esri.Samples", 1, 0, "FeatureLayerExtrusionSample");
}

void FeatureLayerExtrusion::componentComplete()
{
  QQuickItem::componentComplete();

  // Create the feature service to use
  m_featureTable = new ServiceFeatureTable(QUrl("https://sampleserver6.arcgisonline.com/arcgis/rest/services/Census/MapServer/3"), this);

  // add the service feature table to a feature layer
  m_featureLayer = new FeatureLayer(m_featureTable, this);

  // set the feature layer to render dynamically to allow extrusion
  m_featureLayer->setRenderingMode(FeatureRenderingMode::Dynamic);

  // define line and fill symbols for a simple renderer
  m_lineSymbol = new SimpleLineSymbol(SimpleLineSymbolStyle::Solid, QColor("Black"), 1.0f, this);
  m_fillSymbol = new SimpleFillSymbol(SimpleFillSymbolStyle::Solid, QColor("Blue"), m_lineSymbol, this);
  m_renderer = new SimpleRenderer(m_fillSymbol, this);

  // set renderer extrusion mode to absolute to prevent clipping
  RendererSceneProperties props = m_renderer->sceneProperties();
  props.setExtrusionMode(ExtrusionMode::AbsoluteHeight);
  props.setExtrusionExpression("[POP2007] / 10");
  m_renderer->setSceneProperties(props);

  // set the simple renderer to the feature layer
  m_featureLayer->setRenderer(m_renderer);

  // Create a scene and give it to the SceneView
  m_sceneView = findChild<SceneQuickView*>("sceneView");
  Scene* scene = new Scene(Basemap::imagery(this), this);
  Surface* surface = new Surface(this);
  surface->elevationSources()->append(
        new ArcGISTiledElevationSource(
          QUrl("https://elevation3d.arcgis.com/arcgis/rest/services/WorldElevation3D/Terrain3D/ImageServer"),
          this));
  scene->setBaseSurface(surface);
  scene->operationalLayers()->append(m_featureLayer);

  // set initial viewpoint
  const double distance = 12940924;
  const Point lookAtPoint = Point(-99.659448, 20.513652, distance, SpatialReference::wgs84());
  const Camera camera(lookAtPoint, 0, 15, 0);
  const Viewpoint initialVp(lookAtPoint, distance, camera);
  scene->setInitialViewpoint(initialVp);

  // apply initial extrusion
  totalPopulation();

  m_sceneView->setArcGISScene(scene);
}

void FeatureLayerExtrusion::popDensity()
{
  // multiply population density by 5000 to make data legible
  RendererSceneProperties props = m_renderer->sceneProperties();
  props.setExtrusionExpression("([POP07_SQMI] * 5000) + 10000");
  m_renderer->setSceneProperties(props);
}

void FeatureLayerExtrusion::totalPopulation()
{
  // divide total population by 10 to make data legible
  RendererSceneProperties props = m_renderer->sceneProperties();
  props.setExtrusionExpression("[POP2007] / 10");
  m_renderer->setSceneProperties(props);
}

<commit_msg>Update FeatureLayerExtrusion.cpp<commit_after>// [WriteFile Name=FeatureLayerExtrusion, Category=Scenes]
// [Legal]
// Copyright 2017 Esri.

// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
// http://www.apache.org/licenses/LICENSE-2.0

// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
// [Legal]

#include "FeatureLayerExtrusion.h"

#include "FeatureLayer.h"
#include "ServiceFeatureTable.h"
#include "ArcGISTiledElevationSource.h"
#include "Scene.h"
#include "SceneQuickView.h"
#include "Point.h"
#include "SimpleLineSymbol.h"
#include "SimpleFillSymbol.h"
#include "SimpleRenderer.h"
#include "RendererSceneProperties.h"

using namespace Esri::ArcGISRuntime;

FeatureLayerExtrusion::FeatureLayerExtrusion(QQuickItem* parent /* = nullptr */):
  QQuickItem(parent)
{
}

void FeatureLayerExtrusion::init()
{
  // Register classes for QML
  qmlRegisterType<SceneQuickView>("Esri.Samples", 1, 0, "SceneView");
  qmlRegisterType<FeatureLayerExtrusion>("Esri.Samples", 1, 0, "FeatureLayerExtrusionSample");
}

void FeatureLayerExtrusion::componentComplete()
{
  QQuickItem::componentComplete();

  // Create the feature service to use
  m_featureTable = new ServiceFeatureTable(QUrl("https://sampleserver6.arcgisonline.com/arcgis/rest/services/Census/MapServer/3"), this);

  // add the service feature table to a feature layer
  m_featureLayer = new FeatureLayer(m_featureTable, this);

  // set the feature layer to render dynamically to allow extrusion
  m_featureLayer->setRenderingMode(FeatureRenderingMode::Dynamic);

  // define line and fill symbols for a simple renderer
  m_lineSymbol = new SimpleLineSymbol(SimpleLineSymbolStyle::Solid, QColor("Black"), 1.0f, this);
  m_fillSymbol = new SimpleFillSymbol(SimpleFillSymbolStyle::Solid, QColor("Blue"), m_lineSymbol, this);
  m_renderer = new SimpleRenderer(m_fillSymbol, this);

  // set renderer extrusion mode to absolute to prevent clipping
  RendererSceneProperties props = m_renderer->sceneProperties();
  props.setExtrusionMode(ExtrusionMode::AbsoluteHeight);
  props.setExtrusionExpression("[POP2007] / 10");
  m_renderer->setSceneProperties(props);

  // set the simple renderer to the feature layer
  m_featureLayer->setRenderer(m_renderer);

  // Create a scene and give it to the SceneView
  m_sceneView = findChild<SceneQuickView*>("sceneView");
  Scene* scene = new Scene(Basemap::imagery(this), this);
  Surface* surface = new Surface(this);
  surface->elevationSources()->append(
        new ArcGISTiledElevationSource(
          QUrl("https://elevation3d.arcgis.com/arcgis/rest/services/WorldElevation3D/Terrain3D/ImageServer"),
          this));
  scene->setBaseSurface(surface);
  scene->operationalLayers()->append(m_featureLayer);

  // set initial viewpoint
  const double distance = 12940924;
  const Point lookAtPoint(-99.659448, 20.513652, distance, SpatialReference::wgs84());
  const Camera camera(lookAtPoint, 0, 15, 0);
  const Viewpoint initialVp(lookAtPoint, distance, camera);
  scene->setInitialViewpoint(initialVp);

  // apply initial extrusion
  totalPopulation();

  m_sceneView->setArcGISScene(scene);
}

void FeatureLayerExtrusion::popDensity()
{
  // multiply population density by 5000 to make data legible
  RendererSceneProperties props = m_renderer->sceneProperties();
  props.setExtrusionExpression("([POP07_SQMI] * 5000) + 10000");
  m_renderer->setSceneProperties(props);
}

void FeatureLayerExtrusion::totalPopulation()
{
  // divide total population by 10 to make data legible
  RendererSceneProperties props = m_renderer->sceneProperties();
  props.setExtrusionExpression("[POP2007] / 10");
  m_renderer->setSceneProperties(props);
}

<|endoftext|>


<commit_before>/******************************************************************************
*       SOFA, Simulation Open-Framework Architecture, version 1.0 beta 4      *
*                (c) 2006-2009 MGH, INRIA, USTL, UJF, CNRS                    *
*                                                                             *
* This library is free software; you can redistribute it and/or modify it     *
* under the terms of the GNU Lesser General Public License as published by    *
* the Free Software Foundation; either version 2.1 of the License, or (at     *
* your option) any later version.                                             *
*                                                                             *
* This library is distributed in the hope that it will be useful, but WITHOUT *
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or       *
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License *
* for more details.                                                           *
*                                                                             *
* You should have received a copy of the GNU Lesser General Public License    *
* along with this library; if not, write to the Free Software Foundation,     *
* Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301 USA.          *
*******************************************************************************
*                               SOFA :: Modules                               *
*                                                                             *
* Authors: The SOFA Team and external contributors (see Authors.txt)          *
*                                                                             *
* Contact information: contact@sofa-framework.org                             *
******************************************************************************/
#ifndef SOFA_COMPONENT_CONSTRAINTSET_PERSISTENTUNILATERALINTERACTIONCONSTRAINT_INL
#define SOFA_COMPONENT_CONSTRAINTSET_PERSISTENTUNILATERALINTERACTIONCONSTRAINT_INL

#include "PersistentUnilateralInteractionConstraint.h"

#include <sofa/component/constraintset/UnilateralInteractionConstraint.inl>

#include <sofa/helper/rmath.h>

namespace sofa
{

namespace component
{

namespace constraintset
{

template< class DataTypes >
void PersistentUnilateralConstraintResolutionWithFriction< DataTypes >::init(int line, double** w, double* force)
{
    _W[0] = w[line		][line		];
    _W[1] = w[line		][line + 1	];
    _W[2] = w[line		][line + 2	];
    _W[3] = w[line + 1	][line + 1	];
    _W[4] = w[line + 1	][line + 2	];
    _W[5] = w[line + 2	][line + 2	];

    ///@TODO OPTIMIZATION
    force[line		] = _f[0];
    force[line + 1	] = _f[1];
    force[line + 2	] = _f[2];
}

template< class DataTypes >
void PersistentUnilateralConstraintResolutionWithFriction< DataTypes >::resolution(int line, double** /*w*/, double* d, double* force, double * /*dfree*/)
{
    double f[2];
    double normFt;

    f[0] = force[line]; f[1] = force[line+1];
    force[line] -= d[line] / _W[0];

    if(force[line] < 0)
    {
        force[line]=0; force[line+1]=0; force[line+2]=0;

        ///@TODO OPTIMIZATION
        if (m_constraint)
            m_constraint->setContactState(line, NONE);

        return;
    }

    d[line+1] += _W[1] * (force[line]-f[0]);
    d[line+2] += _W[2] * (force[line]-f[0]);
    force[line+1] -= 2*d[line+1] / (_W[3] +_W[5]) ;
    force[line+2] -= 2*d[line+2] / (_W[3] +_W[5]) ;

    normFt = sqrt(force[line+1]*force[line+1] + force[line+2]*force[line+2]);

    if(normFt > _mu*force[line])
    {
        force[line+1] *= _mu*force[line]/normFt;
        force[line+2] *= _mu*force[line]/normFt;

        ///@TODO OPTIMIZATION
        if (m_constraint)
        {
            m_constraint->setContactState(line, SLIDING);
            m_constraint->setContactForce(line, Deriv(force[line], force[line+1], force[line+2]));
        }
    }
    else
    {
        ///@TODO OPTIMIZATION
        if (m_constraint)
        {
            m_constraint->setContactState(line, STICKY);
            m_constraint->setContactForce(line, Deriv(force[line], force[line+1], force[line+2]));
        }
    }
}

template< class DataTypes >
void PersistentUnilateralConstraintResolutionWithFriction< DataTypes >::store(int line, double* force, bool /*convergence*/)
{
    if(_active)
    {
        *_active = (force[line] != 0);

        // Won't be used in the haptic thread
        _active = NULL;
    }
}

template<class DataTypes>
void PersistentUnilateralInteractionConstraint<DataTypes>::addContact(double mu, Deriv norm, Coord P, Coord Q, Real contactDistance, int m1, int m2, Coord Pfree, Coord Qfree, long id, PersistentID localid, bool isPersistent)
{
    // Compute dt and delta
    const Real delta = dot(P-Q, norm) - contactDistance;
    const Real deltaFree = dot(Pfree-Qfree, norm) - contactDistance;

    if (this->f_printLog.getValue())
    {
        std::cout << "delta : " << delta << " - deltaFree : " << deltaFree << std::endl;
        std::cout << "P : " << P << " - PFree : " << Pfree << std::endl;
        std::cout << "Q : " << Q << " - QFree : " << Qfree << std::endl;
    }

    unsigned int lastContactIndex = this->contacts.size();
    this->contacts.resize(lastContactIndex + 1);

    typename Inherited::Contact& c = this->contacts[lastContactIndex];

    c.P				= P;
    c.Q				= Q;
    c.Pfree			= Pfree;
    c.Qfree			= Qfree;
    c.m1			= m1;
    c.m2			= m2;
    c.norm			= norm;
    c.delta			= delta;
    c.mu			= mu;
    c.contactId		= id;
    c.localId		= localid;
    c.t				= Deriv(norm.z(), norm.x(), norm.y());
    c.s				= cross(norm, c.t);
    c.s				= c.s / c.s.norm();
    c.t				= cross((-norm), c.s);

    const Deriv PPfree = Pfree - P;
    const Deriv QQfree = Qfree - Q;
    const Real REF_DIST = PPfree.norm() + QQfree.norm();

    if (isPersistent)
    {

        std::cout << "Persistent contact: \nP : " << P << " - PFree : " << Pfree << std::endl;
        std::cout << "Q : " << Q << " - QFree : " << Qfree << std::endl;
        c.dfree		= deltaFree;
        c.dfree_t	= dot(Pfree - Qfree, c.t);
        c.dfree_s	= dot(Pfree - Qfree, c.s);

        return;
    }

    if (helper::rabs(delta) < 0.00001 * REF_DIST)
    {
        c.dfree		= deltaFree;
        c.dfree_t	= dot(PPfree, c.t) - dot(QQfree, c.t);
        c.dfree_s	= dot(PPfree, c.s) - dot(QQfree, c.s);

        return;
    }

    if (helper::rabs(delta - deltaFree) > 0.001 * delta)
    {
        const Real dt = delta / (delta - deltaFree);

        if (dt > 0.0 && dt < 1.0)
        {
            const sofa::defaulttype::Vector3 Qt = Q * (1-dt) + Qfree * dt;
            const sofa::defaulttype::Vector3 Pt = P * (1-dt) + Pfree * dt;

            c.dfree		= deltaFree;
            c.dfree_t	= dot(Pfree-Pt, c.t) - dot(Qfree-Qt, c.t);
            c.dfree_s	= dot(Pfree-Pt, c.s) - dot(Qfree-Qt, c.s);
        }
        else
        {
            if (deltaFree < 0.0)
            {
                c.dfree		= deltaFree;
                c.dfree_t	= dot(PPfree, c.t) - dot(QQfree, c.t);
                c.dfree_s	= dot(PPfree, c.s) - dot(QQfree, c.s);
            }
            else
            {
                c.dfree		= deltaFree;
                c.dfree_t	= 0;
                c.dfree_s	= 0;
            }
        }
    }
    else
    {
        c.dfree		= deltaFree;
        c.dfree_t	= dot(PPfree, c.t) - dot(QQfree, c.t);
        c.dfree_s	= dot(PPfree, c.s) - dot(QQfree, c.s);
    }
}

template<class DataTypes>
void PersistentUnilateralInteractionConstraint<DataTypes>::getConstraintResolution(std::vector<core::behavior::ConstraintResolution*>& resTab, unsigned int& offset)
{
    if (this->contactsStatus)
        delete[] this->contactsStatus;

    this->contactsStatus = new bool[this->contacts.size()];
    memset(this->contactsStatus, 0, sizeof(bool)*this->contacts.size());

    for(unsigned int i=0; i<this->contacts.size(); i++)
    {
        Contact& c = this->contacts[i];
        if(c.mu > 0.0)
        {
            PersistentUnilateralConstraintResolutionWithFriction<DataTypes> *cRes = new PersistentUnilateralConstraintResolutionWithFriction<DataTypes>(c.mu, &this->contactsStatus[i]);
            cRes->setConstraint(this);
            cRes->setInitForce(getInitForce(c.contactId));
            resTab[offset] = cRes;
            offset += 3;
        }
        else
            resTab[offset++] = new UnilateralConstraintResolution();
    }
}

template<class DataTypes>
bool PersistentUnilateralInteractionConstraint<DataTypes>::isSticked(int _contactId)
{
    typename sofa::helper::vector< Contact >::iterator it = this->contacts.begin();
    typename sofa::helper::vector< Contact >::iterator itEnd = this->contacts.end();

    while (it != itEnd)
    {
        if (it->contactId == _contactId)
            break;

        ++it;
    }

    if (it != itEnd)
        return (contactStates[it->id] == PersistentUnilateralConstraintResolutionWithFriction<DataTypes>::STICKY);
    else
        return false;
}

template<class DataTypes>
void PersistentUnilateralInteractionConstraint<DataTypes>::setContactState(int id, ContactState s)
{
    if (contactStates.find(id) != contactStates.end())
    {
        contactStates[id] = s;
    }
    else
    {
        contactStates.insert(std::make_pair(id, s));
    }
}

template<class DataTypes>
void PersistentUnilateralInteractionConstraint<DataTypes>::clearContactStates()
{
    contactStates.clear();
}

template<class DataTypes>
void PersistentUnilateralInteractionConstraint<DataTypes>::setContactForce(int id, Deriv f)
{
    if (contactForces.find(id) != contactForces.end())
    {
        contactForces[id] = f;
    }
    else
    {
        contactForces.insert(std::make_pair(id, f));
    }
}

template<class DataTypes>
typename PersistentUnilateralInteractionConstraint<DataTypes>::Deriv PersistentUnilateralInteractionConstraint<DataTypes>::getContactForce(int _contactId)
{
    typename sofa::helper::vector< Contact >::iterator it = this->contacts.begin();
    typename sofa::helper::vector< Contact >::iterator itEnd = this->contacts.end();

    while (it != itEnd)
    {
        if (it->contactId == _contactId)
            break;

        ++it;
    }

    if (it != itEnd)
    {
        if (contactForces.find(it->id) != contactForces.end())
        {
            return contactForces[it->id];
        }
    }

    return Deriv();
}

template<class DataTypes>
void PersistentUnilateralInteractionConstraint<DataTypes>::clearContactForces()
{
    contactForces.clear();
}

template<class DataTypes>
void PersistentUnilateralInteractionConstraint<DataTypes>::setInitForce(int id, Deriv f)
{
    if (initForces.find(id) != initForces.end())
    {
        initForces[id] = f;
    }
    else
    {
        initForces.insert(std::make_pair(id, f));
    }
}

template<class DataTypes>
typename PersistentUnilateralInteractionConstraint<DataTypes>::Deriv PersistentUnilateralInteractionConstraint<DataTypes>::getInitForce(int id)
{
    if (initForces.find(id) != initForces.end())
    {
        return initForces[id];
    }

    return Deriv();
}

template<class DataTypes>
void PersistentUnilateralInteractionConstraint<DataTypes>::clearInitForces()
{
    initForces.clear();
}

template<class DataTypes>
void PersistentUnilateralInteractionConstraint<DataTypes>::debugContactStates()
{
    std::cout << "-------------->debugContactStates\n";

    typename std::map< int, ContactState >::iterator it = contactStates.begin();
    typename std::map< int, ContactState >::iterator itEnd = contactStates.end();

    std::string s;

    while (it != itEnd)
    {
        switch (it->second)
        {
        case PersistentUnilateralConstraintResolutionWithFriction<DataTypes>::NONE :
            s = "NONE";
            break;

        case PersistentUnilateralConstraintResolutionWithFriction<DataTypes>::SLIDING :
            s = "SLIDING";
            break;

        case PersistentUnilateralConstraintResolutionWithFriction<DataTypes>::STICKY :
            s = "STICKY";
            break;
        }

        std::cout << it->first << " : " << s << std::endl;
        ++it;
    }
}

template<class DataTypes>
void PersistentUnilateralInteractionConstraint<DataTypes>::draw()
{
    if (!this->getContext()->getShowInteractionForceFields()) return;

    glDisable(GL_LIGHTING);

    for (unsigned int i=0; i< this->contacts.size(); i++)
    {
        const Contact& c = this->contacts[i];

        glLineWidth(5);
        glBegin(GL_LINES);

        switch (contactStates[c.id])
        {
        case PersistentUnilateralConstraintResolutionWithFriction<DataTypes>::NONE :
            glColor4f(1,0,0,1);
            break;

        case PersistentUnilateralConstraintResolutionWithFriction<DataTypes>::SLIDING :
            glColor4f(0,0,1,1);
            break;

        case PersistentUnilateralConstraintResolutionWithFriction<DataTypes>::STICKY :
            glColor4f(0,1,0,1);
            break;
        }

        helper::gl::glVertexT(c.P);
        helper::gl::glVertexT(c.Q);

        glEnd();

        glLineWidth(1);
        glBegin(GL_LINES);

        glColor4f(1,1,1,1);
        helper::gl::glVertexT(c.Pfree);
        helper::gl::glVertexT(c.Qfree);

        glEnd();

        glLineWidth(1);
    }
}

} // namespace constraintset

} // namespace component

} // namespace sofa

#endif // SOFA_COMPONENT_CONSTRAINTSET_PERSISTENTUNILATERALINTERACTIONCONSTRAINT_INL
<commit_msg>r9767/sofa-dev : FIX : Bug in Haptics Thread trying to access a potentially deleted UnilateralInteractionConstraint.<commit_after>/******************************************************************************
*       SOFA, Simulation Open-Framework Architecture, version 1.0 beta 4      *
*                (c) 2006-2009 MGH, INRIA, USTL, UJF, CNRS                    *
*                                                                             *
* This library is free software; you can redistribute it and/or modify it     *
* under the terms of the GNU Lesser General Public License as published by    *
* the Free Software Foundation; either version 2.1 of the License, or (at     *
* your option) any later version.                                             *
*                                                                             *
* This library is distributed in the hope that it will be useful, but WITHOUT *
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or       *
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License *
* for more details.                                                           *
*                                                                             *
* You should have received a copy of the GNU Lesser General Public License    *
* along with this library; if not, write to the Free Software Foundation,     *
* Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301 USA.          *
*******************************************************************************
*                               SOFA :: Modules                               *
*                                                                             *
* Authors: The SOFA Team and external contributors (see Authors.txt)          *
*                                                                             *
* Contact information: contact@sofa-framework.org                             *
******************************************************************************/
#ifndef SOFA_COMPONENT_CONSTRAINTSET_PERSISTENTUNILATERALINTERACTIONCONSTRAINT_INL
#define SOFA_COMPONENT_CONSTRAINTSET_PERSISTENTUNILATERALINTERACTIONCONSTRAINT_INL

#include "PersistentUnilateralInteractionConstraint.h"

#include <sofa/component/constraintset/UnilateralInteractionConstraint.inl>

#include <sofa/helper/rmath.h>

namespace sofa
{

namespace component
{

namespace constraintset
{

template< class DataTypes >
void PersistentUnilateralConstraintResolutionWithFriction< DataTypes >::init(int line, double** w, double* force)
{
    _W[0] = w[line		][line		];
    _W[1] = w[line		][line + 1	];
    _W[2] = w[line		][line + 2	];
    _W[3] = w[line + 1	][line + 1	];
    _W[4] = w[line + 1	][line + 2	];
    _W[5] = w[line + 2	][line + 2	];

    ///@TODO OPTIMIZATION
    force[line		] = _f[0];
    force[line + 1	] = _f[1];
    force[line + 2	] = _f[2];
}

template< class DataTypes >
void PersistentUnilateralConstraintResolutionWithFriction< DataTypes >::resolution(int line, double** /*w*/, double* d, double* force, double * /*dfree*/)
{
    double f[2];
    double normFt;

    f[0] = force[line]; f[1] = force[line+1];
    force[line] -= d[line] / _W[0];

    if(force[line] < 0)
    {
        force[line]=0; force[line+1]=0; force[line+2]=0;

        ///@TODO OPTIMIZATION
        if (m_constraint)
            m_constraint->setContactState(line, NONE);

        return;
    }

    d[line+1] += _W[1] * (force[line]-f[0]);
    d[line+2] += _W[2] * (force[line]-f[0]);
    force[line+1] -= 2*d[line+1] / (_W[3] +_W[5]) ;
    force[line+2] -= 2*d[line+2] / (_W[3] +_W[5]) ;

    normFt = sqrt(force[line+1]*force[line+1] + force[line+2]*force[line+2]);

    if(normFt > _mu*force[line])
    {
        force[line+1] *= _mu*force[line]/normFt;
        force[line+2] *= _mu*force[line]/normFt;

        ///@TODO OPTIMIZATION
        if (m_constraint)
        {
            m_constraint->setContactState(line, SLIDING);
            m_constraint->setContactForce(line, Deriv(force[line], force[line+1], force[line+2]));
        }
    }
    else
    {
        ///@TODO OPTIMIZATION
        if (m_constraint)
        {
            m_constraint->setContactState(line, STICKY);
            m_constraint->setContactForce(line, Deriv(force[line], force[line+1], force[line+2]));
        }
    }
}

template< class DataTypes >
void PersistentUnilateralConstraintResolutionWithFriction< DataTypes >::store(int line, double* force, bool /*convergence*/)
{
    m_constraint = 0;

    if(_active)
    {
        *_active = (force[line] != 0);

        // Won't be used in the haptic thread
        _active = NULL;
    }
}

template<class DataTypes>
void PersistentUnilateralInteractionConstraint<DataTypes>::addContact(double mu, Deriv norm, Coord P, Coord Q, Real contactDistance, int m1, int m2, Coord Pfree, Coord Qfree, long id, PersistentID localid, bool isPersistent)
{
    // Compute dt and delta
    const Real delta = dot(P-Q, norm) - contactDistance;
    const Real deltaFree = dot(Pfree-Qfree, norm) - contactDistance;

    if (this->f_printLog.getValue())
    {
        std::cout << "delta : " << delta << " - deltaFree : " << deltaFree << std::endl;
        std::cout << "P : " << P << " - PFree : " << Pfree << std::endl;
        std::cout << "Q : " << Q << " - QFree : " << Qfree << std::endl;
    }

    unsigned int lastContactIndex = this->contacts.size();
    this->contacts.resize(lastContactIndex + 1);

    typename Inherited::Contact& c = this->contacts[lastContactIndex];

    c.P				= P;
    c.Q				= Q;
    c.Pfree			= Pfree;
    c.Qfree			= Qfree;
    c.m1			= m1;
    c.m2			= m2;
    c.norm			= norm;
    c.delta			= delta;
    c.mu			= mu;
    c.contactId		= id;
    c.localId		= localid;
    c.t				= Deriv(norm.z(), norm.x(), norm.y());
    c.s				= cross(norm, c.t);
    c.s				= c.s / c.s.norm();
    c.t				= cross((-norm), c.s);

    const Deriv PPfree = Pfree - P;
    const Deriv QQfree = Qfree - Q;
    const Real REF_DIST = PPfree.norm() + QQfree.norm();

    if (isPersistent)
    {

        std::cout << "Persistent contact: \nP : " << P << " - PFree : " << Pfree << std::endl;
        std::cout << "Q : " << Q << " - QFree : " << Qfree << std::endl;
        c.dfree		= deltaFree;
        c.dfree_t	= dot(Pfree - Qfree, c.t);
        c.dfree_s	= dot(Pfree - Qfree, c.s);

        return;
    }

    if (helper::rabs(delta) < 0.00001 * REF_DIST)
    {
        c.dfree		= deltaFree;
        c.dfree_t	= dot(PPfree, c.t) - dot(QQfree, c.t);
        c.dfree_s	= dot(PPfree, c.s) - dot(QQfree, c.s);

        return;
    }

    if (helper::rabs(delta - deltaFree) > 0.001 * delta)
    {
        const Real dt = delta / (delta - deltaFree);

        if (dt > 0.0 && dt < 1.0)
        {
            const sofa::defaulttype::Vector3 Qt = Q * (1-dt) + Qfree * dt;
            const sofa::defaulttype::Vector3 Pt = P * (1-dt) + Pfree * dt;

            c.dfree		= deltaFree;
            c.dfree_t	= dot(Pfree-Pt, c.t) - dot(Qfree-Qt, c.t);
            c.dfree_s	= dot(Pfree-Pt, c.s) - dot(Qfree-Qt, c.s);
        }
        else
        {
            if (deltaFree < 0.0)
            {
                c.dfree		= deltaFree;
                c.dfree_t	= dot(PPfree, c.t) - dot(QQfree, c.t);
                c.dfree_s	= dot(PPfree, c.s) - dot(QQfree, c.s);
            }
            else
            {
                c.dfree		= deltaFree;
                c.dfree_t	= 0;
                c.dfree_s	= 0;
            }
        }
    }
    else
    {
        c.dfree		= deltaFree;
        c.dfree_t	= dot(PPfree, c.t) - dot(QQfree, c.t);
        c.dfree_s	= dot(PPfree, c.s) - dot(QQfree, c.s);
    }
}

template<class DataTypes>
void PersistentUnilateralInteractionConstraint<DataTypes>::getConstraintResolution(std::vector<core::behavior::ConstraintResolution*>& resTab, unsigned int& offset)
{
    if (this->contactsStatus)
        delete[] this->contactsStatus;

    this->contactsStatus = new bool[this->contacts.size()];
    memset(this->contactsStatus, 0, sizeof(bool)*this->contacts.size());

    for(unsigned int i=0; i<this->contacts.size(); i++)
    {
        Contact& c = this->contacts[i];
        if(c.mu > 0.0)
        {
            PersistentUnilateralConstraintResolutionWithFriction<DataTypes> *cRes = new PersistentUnilateralConstraintResolutionWithFriction<DataTypes>(c.mu, &this->contactsStatus[i]);
            cRes->setConstraint(this);
            cRes->setInitForce(getInitForce(c.contactId));
            resTab[offset] = cRes;
            offset += 3;
        }
        else
            resTab[offset++] = new UnilateralConstraintResolution();
    }
}

template<class DataTypes>
bool PersistentUnilateralInteractionConstraint<DataTypes>::isSticked(int _contactId)
{
    typename sofa::helper::vector< Contact >::iterator it = this->contacts.begin();
    typename sofa::helper::vector< Contact >::iterator itEnd = this->contacts.end();

    while (it != itEnd)
    {
        if (it->contactId == _contactId)
            break;

        ++it;
    }

    if (it != itEnd)
        return (contactStates[it->id] == PersistentUnilateralConstraintResolutionWithFriction<DataTypes>::STICKY);
    else
        return false;
}

template<class DataTypes>
void PersistentUnilateralInteractionConstraint<DataTypes>::setContactState(int id, ContactState s)
{
    if (contactStates.find(id) != contactStates.end())
    {
        contactStates[id] = s;
    }
    else
    {
        contactStates.insert(std::make_pair(id, s));
    }
}

template<class DataTypes>
void PersistentUnilateralInteractionConstraint<DataTypes>::clearContactStates()
{
    contactStates.clear();
}

template<class DataTypes>
void PersistentUnilateralInteractionConstraint<DataTypes>::setContactForce(int id, Deriv f)
{
    if (contactForces.find(id) != contactForces.end())
    {
        contactForces[id] = f;
    }
    else
    {
        contactForces.insert(std::make_pair(id, f));
    }
}

template<class DataTypes>
typename PersistentUnilateralInteractionConstraint<DataTypes>::Deriv PersistentUnilateralInteractionConstraint<DataTypes>::getContactForce(int _contactId)
{
    typename sofa::helper::vector< Contact >::iterator it = this->contacts.begin();
    typename sofa::helper::vector< Contact >::iterator itEnd = this->contacts.end();

    while (it != itEnd)
    {
        if (it->contactId == _contactId)
            break;

        ++it;
    }

    if (it != itEnd)
    {
        if (contactForces.find(it->id) != contactForces.end())
        {
            return contactForces[it->id];
        }
    }

    return Deriv();
}

template<class DataTypes>
void PersistentUnilateralInteractionConstraint<DataTypes>::clearContactForces()
{
    contactForces.clear();
}

template<class DataTypes>
void PersistentUnilateralInteractionConstraint<DataTypes>::setInitForce(int id, Deriv f)
{
    if (initForces.find(id) != initForces.end())
    {
        initForces[id] = f;
    }
    else
    {
        initForces.insert(std::make_pair(id, f));
    }
}

template<class DataTypes>
typename PersistentUnilateralInteractionConstraint<DataTypes>::Deriv PersistentUnilateralInteractionConstraint<DataTypes>::getInitForce(int id)
{
    if (initForces.find(id) != initForces.end())
    {
        return initForces[id];
    }

    return Deriv();
}

template<class DataTypes>
void PersistentUnilateralInteractionConstraint<DataTypes>::clearInitForces()
{
    initForces.clear();
}

template<class DataTypes>
void PersistentUnilateralInteractionConstraint<DataTypes>::debugContactStates()
{
    std::cout << "-------------->debugContactStates\n";

    typename std::map< int, ContactState >::iterator it = contactStates.begin();
    typename std::map< int, ContactState >::iterator itEnd = contactStates.end();

    std::string s;

    while (it != itEnd)
    {
        switch (it->second)
        {
        case PersistentUnilateralConstraintResolutionWithFriction<DataTypes>::NONE :
            s = "NONE";
            break;

        case PersistentUnilateralConstraintResolutionWithFriction<DataTypes>::SLIDING :
            s = "SLIDING";
            break;

        case PersistentUnilateralConstraintResolutionWithFriction<DataTypes>::STICKY :
            s = "STICKY";
            break;
        }

        std::cout << it->first << " : " << s << std::endl;
        ++it;
    }
}

template<class DataTypes>
void PersistentUnilateralInteractionConstraint<DataTypes>::draw()
{
    if (!this->getContext()->getShowInteractionForceFields()) return;

    glDisable(GL_LIGHTING);

    for (unsigned int i=0; i< this->contacts.size(); i++)
    {
        const Contact& c = this->contacts[i];

        glLineWidth(5);
        glBegin(GL_LINES);

        switch (contactStates[c.id])
        {
        case PersistentUnilateralConstraintResolutionWithFriction<DataTypes>::NONE :
            glColor4f(1,0,0,1);
            break;

        case PersistentUnilateralConstraintResolutionWithFriction<DataTypes>::SLIDING :
            glColor4f(0,0,1,1);
            break;

        case PersistentUnilateralConstraintResolutionWithFriction<DataTypes>::STICKY :
            glColor4f(0,1,0,1);
            break;
        }

        helper::gl::glVertexT(c.P);
        helper::gl::glVertexT(c.Q);

        glEnd();

        glLineWidth(1);
        glBegin(GL_LINES);

        glColor4f(1,1,1,1);
        helper::gl::glVertexT(c.Pfree);
        helper::gl::glVertexT(c.Qfree);

        glEnd();

        glLineWidth(1);
    }
}

} // namespace constraintset

} // namespace component

} // namespace sofa

#endif // SOFA_COMPONENT_CONSTRAINTSET_PERSISTENTUNILATERALINTERACTIONCONSTRAINT_INL
<|endoftext|>


<commit_before>// Polygon.cpp

#include "Polygon.h"
#include "Triangle.h"
#include "IndexTriangle.h"
#include "LineSegment.h"
#include "Surface.h"
#include "AffineTransform.h"
#include "Graph.h"
#include "Exception.h"
#include "ListFunctions.h"

using namespace _3DMath;

Polygon::Polygon( void )
{
	vertexArray = new VectorArray();
	indexTriangleList = new IndexTriangleList();
}

/*virtual*/ Polygon::~Polygon( void )
{
	delete vertexArray;
	delete indexTriangleList;
}

void Polygon::Transform( const AffineTransform& transform )
{
	transform.Transform( *vertexArray );
}

bool Polygon::GetPlane( Plane& plane ) const
{
	if( vertexArray->size() < 3 )
		return false;

	Vector center;
	GetCenter( center );

	Vector normal;
	normal.Set( 0.0, 0.0, 0.0 );

	for( int i = 0; i < ( signed )vertexArray->size(); i++ )
	{
		// This is the Newel method.
		int j = ( i + 1 ) % vertexArray->size();
		const Vector& pointA = ( *vertexArray )[i];
		const Vector& pointB = ( *vertexArray )[j];
		normal.x += ( pointA.y - pointB.y ) * ( pointA.z + pointB.z );
		normal.y += ( pointA.z - pointB.z ) * ( pointA.x + pointB.x );
		normal.z += ( pointA.x - pointB.x ) * ( pointA.y + pointB.y );
	}

	plane.SetCenterAndNormal( center, normal );
	return true;
}

void Polygon::GetCenter( Vector& center ) const
{
	center.Set( 0.0, 0.0, 0.0 );
	for( int i = 0; i < ( signed )vertexArray->size(); i++ )
		center.Add( ( *vertexArray )[i] );
	center.Scale( 1.0 / double( vertexArray->size() ) );
}

bool Polygon::GetTriangleAverageCenter( Vector& center ) const
{
	if( indexTriangleList->size() == 0 )
		return false;

	center.Set( 0.0, 0.0, 0.0 );

	for( IndexTriangleList::const_iterator iter = indexTriangleList->cbegin(); iter != indexTriangleList->cend(); iter++ )
	{
		const IndexTriangle& indexTriangle = *iter;

		Triangle triangle;
		indexTriangle.GetTriangle( triangle, vertexArray );

		Vector triangleCenter;
		triangle.GetCenter( triangleCenter );

		center.Add( triangleCenter );
	}

	center.Scale( 1.0 / double( indexTriangleList->size() ) );
	return true;
}

// This assumes that we're properly tessellated.
bool Polygon::ContainsPoint( const Vector& point, double eps /*= EPSILON*/ ) const
{
	for( IndexTriangleList::const_iterator iter = indexTriangleList->cbegin(); iter != indexTriangleList->cend(); iter++ )
	{
		const IndexTriangle& indexTriangle = *iter;

		Triangle triangle;
		indexTriangle.GetTriangle( triangle, vertexArray );

		if( triangle.ContainsPoint( point, eps ) )
			return true;
	}

	return false;
}

// Add extraneous points to the polygon until no edge is greater than the given minimum distance.
// Of course, since the geometry of the polygon doesn't change, the visible edge-lengths remain the same.
// Note that this may invalidate a current tessellation of the polygon.
void Polygon::IncreaseDensity( double minDistance )
{
	int i;

	do
	{
		for( i = 0; i < ( signed )vertexArray->size(); i++ )
		{
			int j = ( i + 1 ) % vertexArray->size();
			LineSegment lineSegment;
			lineSegment.vertex[0] = ( *vertexArray )[i];
			lineSegment.vertex[1] = ( *vertexArray )[j];
			if( lineSegment.Length() > minDistance )
			{
				Vector midPoint;
				lineSegment.Lerp( 0.5, midPoint );
				vertexArray->insert( vertexArray->begin() + j, midPoint );
				break;
			}
		}
	}
	while( i < ( signed )vertexArray->size() );
}

// Here we remove any extraneous vertices.  These are those that
// are co-linear with respect to their immediate adjacencies.
// Note that this may invalidate a current tessellation of the polygon.
void Polygon::MinimizeDensity( void )
{
	while( true )
	{
		int i;
		for( i = 0; i < ( signed )vertexArray->size(); i++ )
		{
			Triangle triangle;
			for( int j = 0; j < 3; j++ )
				triangle.vertex[j] = ( *vertexArray )[ ( i + j ) % vertexArray->size() ];

			if( triangle.Area() < EPSILON )
				break;
		}

		if( i == ( signed )vertexArray->size() )
			break;

		vertexArray->erase( vertexArray->begin() + ( i + 1 ) % vertexArray->size() );
	}
}

void Polygon::GetCopy( Polygon& polygon ) const
{
	polygon.vertexArray->clear();
	for( int i = 0; i < ( signed )vertexArray->size(); i++ )
		polygon.vertexArray->push_back( ( *vertexArray )[i] );

	polygon.indexTriangleList->clear();
}

bool Polygon::SplitAgainstSurface( const Surface* surface, PolygonList& polygonList, double minDistance, double maxDistance, double eps /*= EPSILON*/ ) const
{
	Polygon* polygon = new Polygon();
	GetCopy( *polygon );

	PolygonList polygonQueue;
	polygonQueue.push_back( polygon );

	while( polygonQueue.size() > 0 )
	{
		PolygonList::iterator iter = polygonQueue.begin();
		polygon = *iter;
		polygonQueue.erase( iter );

		Polygon* polygonA = nullptr;
		Polygon* polygonB = nullptr;

		if( !polygon->SplitInTwoAgainstSurface( surface, polygonA, polygonB, minDistance, maxDistance, eps ) )
			polygonList.push_back( polygon );
		else
		{
			delete polygon;
			polygonQueue.push_back( polygonA );
			polygonQueue.push_back( polygonB );
		}
	}

	if( polygonQueue.size() > 1 )
		return true;

	FreeList< Polygon >( polygonList );
	return false;
}

bool Polygon::SplitInTwoAgainstSurface( const Surface* surface, Polygon*& polygonA, Polygon*& polygonB, double minDistance, double maxDistance, double eps )
{
	polygonA = nullptr;
	polygonB = nullptr;

	IncreaseDensity( minDistance );

	for( int i = 0; i < ( signed )vertexArray->size(); i++ )
	{
		int j = ( i + 1 ) % vertexArray->size();

		LineSegment lineSegment;
		lineSegment.vertex[0] = ( *vertexArray )[i];
		lineSegment.vertex[1] = ( *vertexArray )[j];

		Surface::Side side[2];
		side[0] = surface->GetSide( lineSegment.vertex[0], eps );
		side[1] = surface->GetSide( lineSegment.vertex[1], eps );

		if( ( side[0] == Surface::INSIDE && side[1] == Surface::OUTSIDE ) ||
			( side[1] == Surface::INSIDE && side[0] == Surface::OUTSIDE ) )
		{
			SurfacePoint* surfacePoint = surface->FindSingleIntersection( lineSegment );
			if( !surfacePoint )
				return false;
			else
			{
				Vector point;
				surfacePoint->GetLocation( point );
				vertexArray->insert( vertexArray->begin() + j, point );
				delete surfacePoint;
			}
		}
	}

	if( !Tessellate() )
		return false;

	std::vector< int > intersectionArray;
	int insideCount = 0;
	int outsideCount = 0;

	for( int i = 0; i < ( signed )vertexArray->size(); i++ )
	{
		Surface::Side side = surface->GetSide( ( *vertexArray )[i] );
		switch( side )
		{
			case Surface::NEITHER_SIDE:
			{
				int j = ( i > 0 ) ? ( i - 1 ) : ( ( signed )vertexArray->size() - 1 );
				int k = ( i + 1 ) % vertexArray->size();

				if( ( surface->GetSide( ( *vertexArray )[j] ) == Surface::INSIDE && surface->GetSide( ( *vertexArray )[k] ) == Surface::OUTSIDE ) ||
					( surface->GetSide( ( *vertexArray )[k] ) == Surface::INSIDE && surface->GetSide( ( *vertexArray )[j] ) == Surface::OUTSIDE ) )
				{
					intersectionArray.push_back(i);
				}

				break;
			}
			case Surface::INSIDE:
			{
				insideCount++;
				break;
			}
			case Surface::OUTSIDE:
			{
				outsideCount++;
				break;
			}
		}
	}

	if( insideCount == 0 || outsideCount == 0 )
		return false;

	_3DMath::Plane plane;
	if( !GetPlane( plane ) )
		return false;

	for( int i = 0; i < ( signed )intersectionArray.size(); i++ )
	{
		for( int j = i + 1; j < ( signed )intersectionArray.size(); j++ )
		{
			Vector pointA = ( *vertexArray )[ intersectionArray[i] ];
			Vector pointB = ( *vertexArray )[ intersectionArray[j] ];

			VectorArray surfacePointArray;
			bool pathFound = false;

			double distance = pointA.Distance( pointB );
			if( distance < eps )
			{
				surfacePointArray.push_back( pointA );
				pathFound = true;
			}
			else
			{
				SurfacePoint* surfacePointA = surface->GetNearestSurfacePoint( pointA );
				SurfacePoint* surfacePointB = surface->GetNearestSurfacePoint( pointB );
				SurfacePoint* surfacePointC = nullptr;

				pathFound = surface->FindDirectPath( surfacePointA, surfacePointB, surfacePointArray, maxDistance, &plane );
				if( !pathFound )
				{
					// This is a bit of a hack.
					Vector center;
					GetCenter( center );

					surfacePointC = surface->GetNearestSurfacePoint( center );
					pathFound = surface->FindDirectPath( surfacePointA, surfacePointC, surfacePointArray, maxDistance, &plane );
					if( pathFound )
					{
						surfacePointArray.pop_back();
						pathFound = surface->FindDirectPath( surfacePointC, surfacePointB, surfacePointArray, maxDistance, &plane );
					}
				}

				delete surfacePointA;
				delete surfacePointB;
				delete surfacePointC;

				if( surfacePointArray.size() == 0 )
					pathFound = false;
			}

			// Does the path along the surface and in the plane of the polygon
			// stay within the polygon's area through the whole path?
			if( pathFound )
			{
				for( int k = 0; k < ( signed )surfacePointArray.size(); i++ )
				{
					if( !ContainsPoint( surfacePointArray[k] ) )
					{
						pathFound = false;
						break;
					}
				}

				if( pathFound )
				{
					for( int k = 0; k < ( signed )surfacePointArray.size() - 1; i++ )
					{
						LineSegment lineSegment;
						lineSegment.vertex[0] = surfacePointArray[k];
						lineSegment.vertex[1] = surfacePointArray[ k + 1 ];

						VectorList intersectionList;
						if( GetIntersectionPoints( lineSegment, intersectionList ) )
						{
							pathFound = false;
							break;
						}
					}
				}
			}

			// Finally, if we get here, we're ready to split the polygon in two.
			if( pathFound )
			{
				polygonA = new Polygon();
				polygonB = new Polygon();

				int k = ( intersectionArray[i] + 1 ) % vertexArray->size();
				while( k != intersectionArray[j] )
				{
					polygonA->vertexArray->push_back( ( *vertexArray )[k] );
					k = ( k + 1 ) % vertexArray->size();
				}

				k = ( intersectionArray[j] + 1 ) % vertexArray->size();
				while( k != intersectionArray[i] )
				{
					polygonB->vertexArray->push_back( ( *vertexArray )[k] );
					k = ( k + 1 ) % vertexArray->size();
				}

				for( int k = 0; k < ( signed )surfacePointArray.size(); k++ )
				{
					int l = signed( surfacePointArray.size() ) - 1 - k;
					polygonA->vertexArray->push_back( surfacePointArray[l] );
					polygonB->vertexArray->push_back( surfacePointArray[k] );
				}

				return true;
			}
		}
	}

	return false;
}

bool Polygon::GetIntersectionPoints( const LineSegment& lineSegment, VectorList& intersectionList ) const
{
	for( int i = 0; i < ( signed )vertexArray->size(); i++ )
	{
		int j = ( i + 1 ) % vertexArray->size();

		LineSegment edge;
		edge.vertex[0] = ( *vertexArray )[i];
		edge.vertex[1] = ( *vertexArray )[j];

		Vector intersectionPoint;
		if( edge.IntersectsWith( lineSegment, &intersectionPoint ) )
			intersectionList.push_back( intersectionPoint );
	}

	return( intersectionList.size() > 0 ? true : false );
}

double Polygon::GetArea( void ) const
{
	double totalArea = 0.0;

	for( IndexTriangleList::const_iterator iter = indexTriangleList->cbegin(); iter != indexTriangleList->end(); iter++ )
	{
		const IndexTriangle& indexTriangle = *iter;
		Triangle triangle;
		indexTriangle.GetTriangle( triangle, vertexArray );
		totalArea += triangle.Area();
	}

	return totalArea;
}

bool Polygon::Tessellate( void ) const
{
	Plane plane;
	if( !GetPlane( plane ) )
		return false;

	indexTriangleList->clear();

	std::vector< int > indexArray;
	for( int i = 0; i < ( signed )vertexArray->size(); i++ )
		indexArray.push_back(i);

	while( indexArray.size() > 2 )
	{
		int i;
		for( i = 0; i < ( signed )indexArray.size(); i++ )
		{
			IndexTriangle indexTriangle(
					indexArray[i],
					indexArray[ ( i + 1 ) % indexArray.size() ],
					indexArray[ ( i + 2 ) % indexArray.size() ] );

			Triangle triangle;
			indexTriangle.GetTriangle( triangle, vertexArray );

			Vector edge[2];
			edge[0].Subtract( triangle.vertex[1], triangle.vertex[0] );
			edge[1].Subtract( triangle.vertex[2], triangle.vertex[1] );

			Vector cross;
			cross.Cross( edge[0], edge[1] );
			double dot = cross.Dot( plane.normal );
			if( dot < 0.0 )
				continue;

			int j;
			for( j = 0; j < ( signed )indexArray.size(); j++ )
			{
				if( j == i || j == ( i + 1 ) % indexArray.size() || j == ( i + 2 ) % indexArray.size() )
					continue;
				if( triangle.ContainsPoint( ( *vertexArray )[ indexArray[j] ] ) )
					break;
			}

			if( j < ( signed )indexArray.size() )
				continue;

			indexTriangleList->push_back( indexTriangle );
			indexArray.erase( indexArray.begin() + ( i + 1 ) % indexArray.size() );
			break;
		}

		if( i == ( signed )indexArray.size() )
			return false;		// Avoid an infinite loop.
	}

	return true;
}

// Polygon.cpp<commit_msg>only check appropriate intersection pairs<commit_after>// Polygon.cpp

#include "Polygon.h"
#include "Triangle.h"
#include "IndexTriangle.h"
#include "LineSegment.h"
#include "Surface.h"
#include "AffineTransform.h"
#include "Graph.h"
#include "Exception.h"
#include "ListFunctions.h"

using namespace _3DMath;

Polygon::Polygon( void )
{
	vertexArray = new VectorArray();
	indexTriangleList = new IndexTriangleList();
}

/*virtual*/ Polygon::~Polygon( void )
{
	delete vertexArray;
	delete indexTriangleList;
}

void Polygon::Transform( const AffineTransform& transform )
{
	transform.Transform( *vertexArray );
}

bool Polygon::GetPlane( Plane& plane ) const
{
	if( vertexArray->size() < 3 )
		return false;

	Vector center;
	GetCenter( center );

	Vector normal;
	normal.Set( 0.0, 0.0, 0.0 );

	for( int i = 0; i < ( signed )vertexArray->size(); i++ )
	{
		// This is the Newel method.
		int j = ( i + 1 ) % vertexArray->size();
		const Vector& pointA = ( *vertexArray )[i];
		const Vector& pointB = ( *vertexArray )[j];
		normal.x += ( pointA.y - pointB.y ) * ( pointA.z + pointB.z );
		normal.y += ( pointA.z - pointB.z ) * ( pointA.x + pointB.x );
		normal.z += ( pointA.x - pointB.x ) * ( pointA.y + pointB.y );
	}

	plane.SetCenterAndNormal( center, normal );
	return true;
}

void Polygon::GetCenter( Vector& center ) const
{
	center.Set( 0.0, 0.0, 0.0 );
	for( int i = 0; i < ( signed )vertexArray->size(); i++ )
		center.Add( ( *vertexArray )[i] );
	center.Scale( 1.0 / double( vertexArray->size() ) );
}

bool Polygon::GetTriangleAverageCenter( Vector& center ) const
{
	if( indexTriangleList->size() == 0 )
		return false;

	center.Set( 0.0, 0.0, 0.0 );

	for( IndexTriangleList::const_iterator iter = indexTriangleList->cbegin(); iter != indexTriangleList->cend(); iter++ )
	{
		const IndexTriangle& indexTriangle = *iter;

		Triangle triangle;
		indexTriangle.GetTriangle( triangle, vertexArray );

		Vector triangleCenter;
		triangle.GetCenter( triangleCenter );

		center.Add( triangleCenter );
	}

	center.Scale( 1.0 / double( indexTriangleList->size() ) );
	return true;
}

// This assumes that we're properly tessellated.
bool Polygon::ContainsPoint( const Vector& point, double eps /*= EPSILON*/ ) const
{
	for( IndexTriangleList::const_iterator iter = indexTriangleList->cbegin(); iter != indexTriangleList->cend(); iter++ )
	{
		const IndexTriangle& indexTriangle = *iter;

		Triangle triangle;
		indexTriangle.GetTriangle( triangle, vertexArray );

		if( triangle.ContainsPoint( point, eps ) )
			return true;
	}

	return false;
}

// Add extraneous points to the polygon until no edge is greater than the given minimum distance.
// Of course, since the geometry of the polygon doesn't change, the visible edge-lengths remain the same.
// Note that this may invalidate a current tessellation of the polygon.
void Polygon::IncreaseDensity( double minDistance )
{
	int i;

	do
	{
		for( i = 0; i < ( signed )vertexArray->size(); i++ )
		{
			int j = ( i + 1 ) % vertexArray->size();
			LineSegment lineSegment;
			lineSegment.vertex[0] = ( *vertexArray )[i];
			lineSegment.vertex[1] = ( *vertexArray )[j];
			if( lineSegment.Length() > minDistance )
			{
				Vector midPoint;
				lineSegment.Lerp( 0.5, midPoint );
				vertexArray->insert( vertexArray->begin() + j, midPoint );
				break;
			}
		}
	}
	while( i < ( signed )vertexArray->size() );
}

// Here we remove any extraneous vertices.  These are those that
// are co-linear with respect to their immediate adjacencies.
// Note that this may invalidate a current tessellation of the polygon.
void Polygon::MinimizeDensity( void )
{
	while( true )
	{
		int i;
		for( i = 0; i < ( signed )vertexArray->size(); i++ )
		{
			Triangle triangle;
			for( int j = 0; j < 3; j++ )
				triangle.vertex[j] = ( *vertexArray )[ ( i + j ) % vertexArray->size() ];

			if( triangle.Area() < EPSILON )
				break;
		}

		if( i == ( signed )vertexArray->size() )
			break;

		vertexArray->erase( vertexArray->begin() + ( i + 1 ) % vertexArray->size() );
	}
}

void Polygon::GetCopy( Polygon& polygon ) const
{
	polygon.vertexArray->clear();
	for( int i = 0; i < ( signed )vertexArray->size(); i++ )
		polygon.vertexArray->push_back( ( *vertexArray )[i] );

	polygon.indexTriangleList->clear();
}

bool Polygon::SplitAgainstSurface( const Surface* surface, PolygonList& polygonList, double minDistance, double maxDistance, double eps /*= EPSILON*/ ) const
{
	Polygon* polygon = new Polygon();
	GetCopy( *polygon );

	PolygonList polygonQueue;
	polygonQueue.push_back( polygon );

	while( polygonQueue.size() > 0 )
	{
		PolygonList::iterator iter = polygonQueue.begin();
		polygon = *iter;
		polygonQueue.erase( iter );

		Polygon* polygonA = nullptr;
		Polygon* polygonB = nullptr;

		if( !polygon->SplitInTwoAgainstSurface( surface, polygonA, polygonB, minDistance, maxDistance, eps ) )
			polygonList.push_back( polygon );
		else
		{
			delete polygon;
			polygonQueue.push_back( polygonA );
			polygonQueue.push_back( polygonB );
		}
	}

	if( polygonQueue.size() > 1 )
		return true;

	FreeList< Polygon >( polygonList );
	return false;
}

bool Polygon::SplitInTwoAgainstSurface( const Surface* surface, Polygon*& polygonA, Polygon*& polygonB, double minDistance, double maxDistance, double eps )
{
	polygonA = nullptr;
	polygonB = nullptr;

	IncreaseDensity( minDistance );

	for( int i = 0; i < ( signed )vertexArray->size(); i++ )
	{
		int j = ( i + 1 ) % vertexArray->size();

		LineSegment lineSegment;
		lineSegment.vertex[0] = ( *vertexArray )[i];
		lineSegment.vertex[1] = ( *vertexArray )[j];

		Surface::Side side[2];
		side[0] = surface->GetSide( lineSegment.vertex[0], eps );
		side[1] = surface->GetSide( lineSegment.vertex[1], eps );

		if( ( side[0] == Surface::INSIDE && side[1] == Surface::OUTSIDE ) ||
			( side[1] == Surface::INSIDE && side[0] == Surface::OUTSIDE ) )
		{
			SurfacePoint* surfacePoint = surface->FindSingleIntersection( lineSegment );
			if( !surfacePoint )
				return false;
			else
			{
				Vector point;
				surfacePoint->GetLocation( point );
				vertexArray->insert( vertexArray->begin() + j, point );
				delete surfacePoint;
			}
		}
	}

	if( !Tessellate() )
		return false;

	std::vector< int > intersectionArray;
	int insideCount = 0;
	int outsideCount = 0;

	for( int i = 0; i < ( signed )vertexArray->size(); i++ )
	{
		Surface::Side side = surface->GetSide( ( *vertexArray )[i] );
		switch( side )
		{
			case Surface::NEITHER_SIDE:
			{
				int j = ( i > 0 ) ? ( i - 1 ) : ( ( signed )vertexArray->size() - 1 );
				int k = ( i + 1 ) % vertexArray->size();

				if( ( surface->GetSide( ( *vertexArray )[j] ) == Surface::INSIDE && surface->GetSide( ( *vertexArray )[k] ) == Surface::OUTSIDE ) ||
					( surface->GetSide( ( *vertexArray )[k] ) == Surface::INSIDE && surface->GetSide( ( *vertexArray )[j] ) == Surface::OUTSIDE ) )
				{
					intersectionArray.push_back(i);
				}

				break;
			}
			case Surface::INSIDE:
			{
				insideCount++;
				break;
			}
			case Surface::OUTSIDE:
			{
				outsideCount++;
				break;
			}
		}
	}

	if( insideCount == 0 || outsideCount == 0 )
		return false;

	_3DMath::Plane plane;
	if( !GetPlane( plane ) )
		return false;

	for( int i = 0; i < ( signed )intersectionArray.size(); i++ )
	{
		int j = ( i + 1 ) % intersectionArray.size();

		Vector pointA = ( *vertexArray )[ intersectionArray[i] ];
		Vector pointB = ( *vertexArray )[ intersectionArray[j] ];

		VectorArray surfacePointArray;
		bool pathFound = false;

		double distance = pointA.Distance( pointB );
		if( distance < eps )
		{
			surfacePointArray.push_back( pointA );
			pathFound = true;
		}
		else
		{
			SurfacePoint* surfacePointA = surface->GetNearestSurfacePoint( pointA );
			SurfacePoint* surfacePointB = surface->GetNearestSurfacePoint( pointB );
			SurfacePoint* surfacePointC = nullptr;

			pathFound = surface->FindDirectPath( surfacePointA, surfacePointB, surfacePointArray, maxDistance, &plane );
			if( !pathFound )
			{
				// This is a bit of a hack.
				Vector center;
				GetCenter( center );

				surfacePointC = surface->GetNearestSurfacePoint( center );
				pathFound = surface->FindDirectPath( surfacePointA, surfacePointC, surfacePointArray, maxDistance, &plane );
				if( pathFound )
				{
					surfacePointArray.pop_back();
					pathFound = surface->FindDirectPath( surfacePointC, surfacePointB, surfacePointArray, maxDistance, &plane );
				}
			}

			delete surfacePointA;
			delete surfacePointB;
			delete surfacePointC;

			if( surfacePointArray.size() == 0 )
				pathFound = false;
		}

		// Does the path along the surface and in the plane of the polygon
		// stay within the polygon's area through the whole path?
		if( pathFound )
		{
			for( int k = 0; k < ( signed )surfacePointArray.size(); i++ )
			{
				if( !ContainsPoint( surfacePointArray[k] ) )
				{
					pathFound = false;
					break;
				}
			}

			if( pathFound )
			{
				for( int k = 0; k < ( signed )surfacePointArray.size() - 1; i++ )
				{
					LineSegment lineSegment;
					lineSegment.vertex[0] = surfacePointArray[k];
					lineSegment.vertex[1] = surfacePointArray[ k + 1 ];

					VectorList intersectionList;
					if( GetIntersectionPoints( lineSegment, intersectionList ) )
					{
						pathFound = false;
						break;
					}
				}
			}
		}

		// Finally, if we get here, we're ready to split the polygon in two.
		if( pathFound )
		{
			polygonA = new Polygon();
			polygonB = new Polygon();

			int k = ( intersectionArray[i] + 1 ) % vertexArray->size();
			while( k != intersectionArray[j] )
			{
				polygonA->vertexArray->push_back( ( *vertexArray )[k] );
				k = ( k + 1 ) % vertexArray->size();
			}

			k = ( intersectionArray[j] + 1 ) % vertexArray->size();
			while( k != intersectionArray[i] )
			{
				polygonB->vertexArray->push_back( ( *vertexArray )[k] );
				k = ( k + 1 ) % vertexArray->size();
			}

			for( int k = 0; k < ( signed )surfacePointArray.size(); k++ )
			{
				int l = signed( surfacePointArray.size() ) - 1 - k;
				polygonA->vertexArray->push_back( surfacePointArray[l] );
				polygonB->vertexArray->push_back( surfacePointArray[k] );
			}

			return true;
		}
	}

	return false;
}

bool Polygon::GetIntersectionPoints( const LineSegment& lineSegment, VectorList& intersectionList ) const
{
	for( int i = 0; i < ( signed )vertexArray->size(); i++ )
	{
		int j = ( i + 1 ) % vertexArray->size();

		LineSegment edge;
		edge.vertex[0] = ( *vertexArray )[i];
		edge.vertex[1] = ( *vertexArray )[j];

		Vector intersectionPoint;
		if( edge.IntersectsWith( lineSegment, &intersectionPoint ) )
			intersectionList.push_back( intersectionPoint );
	}

	return( intersectionList.size() > 0 ? true : false );
}

double Polygon::GetArea( void ) const
{
	double totalArea = 0.0;

	for( IndexTriangleList::const_iterator iter = indexTriangleList->cbegin(); iter != indexTriangleList->end(); iter++ )
	{
		const IndexTriangle& indexTriangle = *iter;
		Triangle triangle;
		indexTriangle.GetTriangle( triangle, vertexArray );
		totalArea += triangle.Area();
	}

	return totalArea;
}

bool Polygon::Tessellate( void ) const
{
	Plane plane;
	if( !GetPlane( plane ) )
		return false;

	indexTriangleList->clear();

	std::vector< int > indexArray;
	for( int i = 0; i < ( signed )vertexArray->size(); i++ )
		indexArray.push_back(i);

	while( indexArray.size() > 2 )
	{
		int i;
		for( i = 0; i < ( signed )indexArray.size(); i++ )
		{
			IndexTriangle indexTriangle(
					indexArray[i],
					indexArray[ ( i + 1 ) % indexArray.size() ],
					indexArray[ ( i + 2 ) % indexArray.size() ] );

			Triangle triangle;
			indexTriangle.GetTriangle( triangle, vertexArray );

			Vector edge[2];
			edge[0].Subtract( triangle.vertex[1], triangle.vertex[0] );
			edge[1].Subtract( triangle.vertex[2], triangle.vertex[1] );

			Vector cross;
			cross.Cross( edge[0], edge[1] );
			double dot = cross.Dot( plane.normal );
			if( dot < 0.0 )
				continue;

			int j;
			for( j = 0; j < ( signed )indexArray.size(); j++ )
			{
				if( j == i || j == ( i + 1 ) % indexArray.size() || j == ( i + 2 ) % indexArray.size() )
					continue;
				if( triangle.ContainsPoint( ( *vertexArray )[ indexArray[j] ] ) )
					break;
			}

			if( j < ( signed )indexArray.size() )
				continue;

			indexTriangleList->push_back( indexTriangle );
			indexArray.erase( indexArray.begin() + ( i + 1 ) % indexArray.size() );
			break;
		}

		if( i == ( signed )indexArray.size() )
			return false;		// Avoid an infinite loop.
	}

	return true;
}

// Polygon.cpp<|endoftext|>